diff --git a/.gitignore b/.gitignore index d6c37bdfdb..cc97ddf297 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ xcuserdata MSAL.xcscmblueprint .DS_Store *.pyc +## Build generated +build/ +DerivedData/ diff --git a/.travis.yml b/.travis.yml index 8b6e1c2faf..709f9480ec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: objective-c -osx_image: xcode10 +osx_image: xcode10.2 # Set up our rubygems (slather and xcpretty, namely) install: diff --git a/CHANGELOG.md b/CHANGELOG.md index e5fa26a529..e102c6d580 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.5.0] - 2019-07-30 +### Updated +- Added initial macOS support +- Better resolution of authorities for silent token acquisition +- Added backward compatibility for legacy account storages +- Added backward compatibility for ADAL macOS cache + ## [0.4.3] - 2019-05-24 ### Updated - Updated to newer v2 broker protocol version @@ -16,6 +23,16 @@ - Added support for custom B2C domains - Improved MSAL error handling +## [0.3.4] - 2019-03-07 +### Fixed +- Improve logging for token removal scenarios +- Use ASCII for PKCE code challenge +- Don't return Access token if ID token/Account are missing + +## [0.3.3] - 2019-05-29 +### Updated +- Ignore cached fields in JSON if they contains "null" + ## [0.3.2] - 2019-05-24 ### Updated - Updated to newer v2 broker protocol version diff --git a/MSAL.podspec b/MSAL.podspec index e17094e5f0..3db3d86f34 100644 --- a/MSAL.podspec +++ b/MSAL.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "MSAL" - s.version = "0.4.3" + s.version = "0.5.0" s.summary = "Microsoft Authentication Library (MSAL) Preview for iOS" s.description = <<-DESC @@ -30,7 +30,7 @@ Pod::Spec.new do |s| s.subspec 'app-lib' do |app| app.source_files = "MSAL/src/**/*.{h,m}", "MSAL/IdentityCore/IdentityCore/src/**/*.{h,m}" - app.ios.public_header_files = "MSAL/src/public/*.h","MSAL/src/public/ios/*.h", "MSAL/src/public/configuration/**/*.h" + app.ios.public_header_files = "MSAL/src/public/*.h","MSAL/src/public/ios/**/*.h", "MSAL/src/public/configuration/**/*.h" app.osx.public_header_files = "MSAL/src/public/mac/*.h","MSAL/src/public/*.h", "MSAL/src/public/configuration/**/*.h" app.ios.exclude_files = "MSAL/src/**/mac/*", "MSAL/IdentityCore/IdentityCore/src/**/mac/*" @@ -43,14 +43,14 @@ Pod::Spec.new do |s| s.subspec 'extension' do |ext| ext.compiler_flags = '-DADAL_EXTENSION_SAFE=1' ext.source_files = "MSAL/src/**/*.{h,m}", "MSAL/IdentityCore/IdentityCore/src/**/*.{h,m}" - ext.ios.public_header_files = "MSAL/src/public/*.h","MSAL/src/public/ios/*.h", "MSAL/src/public/configuration/**/*.h" + ext.ios.public_header_files = "MSAL/src/public/*.h","MSAL/src/public/ios/**/*.h", "MSAL/src/public/configuration/**/*.h" ext.osx.public_header_files = "MSAL/src/public/mac/*.h","MSAL/src/public/*.h", "MSAL/src/public/configuration/**/*.h" # There is currently a bug in CocoaPods where it doesn't combine the public headers # for both the platform and overall. ext.ios.exclude_files = "MSAL/src/**/mac/*", "MSAL/IdentityCore/IdentityCore/src/**/mac/*" ext.osx.exclude_files = "MSAL/src/**/ios/*", "MSAL/IdentityCore/IdentityCore/src/**/ios/*" - ext.requires_arc = true end + end diff --git a/MSAL/IdentityCore b/MSAL/IdentityCore index 7058feec4e..2dafa2eb41 160000 --- a/MSAL/IdentityCore +++ b/MSAL/IdentityCore @@ -1 +1 @@ -Subproject commit 7058feec4e4fb3d231b1f3ce20775a3deb818bf7 +Subproject commit 2dafa2eb41643c0633611729470dd2a495c3a7b1 diff --git a/MSAL/MSAL.xcodeproj/project.pbxproj b/MSAL/MSAL.xcodeproj/project.pbxproj index 6da963de80..3d41a4e886 100644 --- a/MSAL/MSAL.xcodeproj/project.pbxproj +++ b/MSAL/MSAL.xcodeproj/project.pbxproj @@ -40,14 +40,12 @@ 04A6B5D0226937810035C7C2 /* MSALRedirectUriVerifier.h in Headers */ = {isa = PBXBuildFile; fileRef = B21E07AF210E542C007E3A3C /* MSALRedirectUriVerifier.h */; }; 04A6B5D1226937850035C7C2 /* MSALRedirectUriVerifier.m in Sources */ = {isa = PBXBuildFile; fileRef = B21E07B0210E542C007E3A3C /* MSALRedirectUriVerifier.m */; }; 04A6B5D2226937890035C7C2 /* MSALRedirectUriVerifier.m in Sources */ = {isa = PBXBuildFile; fileRef = B21E07BC210E5458007E3A3C /* MSALRedirectUriVerifier.m */; }; - 04A6B5D32269378E0035C7C2 /* MSALDefaultDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = E02396D21E776F10004D6278 /* MSALDefaultDispatcher.m */; }; - 04A6B5D42269378F0035C7C2 /* MSALDefaultDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = E02396D21E776F10004D6278 /* MSALDefaultDispatcher.m */; }; 04A6B5D5226937930035C7C2 /* MSALTelemetry.m in Sources */ = {isa = PBXBuildFile; fileRef = 96D9A5471E4AB22900674A85 /* MSALTelemetry.m */; }; 04A6B5D6226937940035C7C2 /* MSALTelemetry.m in Sources */ = {isa = PBXBuildFile; fileRef = 96D9A5471E4AB22900674A85 /* MSALTelemetry.m */; }; - 04A6B5D7226937980035C7C2 /* MSALTelemetryDefaultEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = B2B5F08A1FCA61EB00F6AFAD /* MSALTelemetryDefaultEvent.m */; }; - 04A6B5D8226937990035C7C2 /* MSALTelemetryDefaultEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = B2B5F08A1FCA61EB00F6AFAD /* MSALTelemetryDefaultEvent.m */; }; - 04A6B5D92269379B0035C7C2 /* MSALTelemetryDefaultEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = B2B5F0891FCA61EB00F6AFAD /* MSALTelemetryDefaultEvent.h */; }; - 04A6B5DA2269379C0035C7C2 /* MSALTelemetryDefaultEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = B2B5F0891FCA61EB00F6AFAD /* MSALTelemetryDefaultEvent.h */; }; + 04A6B5D7226937980035C7C2 /* (null) in Sources */ = {isa = PBXBuildFile; }; + 04A6B5D8226937990035C7C2 /* (null) in Sources */ = {isa = PBXBuildFile; }; + 04A6B5D92269379B0035C7C2 /* (null) in Headers */ = {isa = PBXBuildFile; }; + 04A6B5DA2269379C0035C7C2 /* (null) in Headers */ = {isa = PBXBuildFile; }; 04A6B5DD226937AA0035C7C2 /* MSALAccountsProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = B2A3C2882145FD0F0082525C /* MSALAccountsProvider.m */; }; 04A6B5DE226937AA0035C7C2 /* MSALAccountsProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = B2A3C2882145FD0F0082525C /* MSALAccountsProvider.m */; }; 04A6B5DF226937AC0035C7C2 /* MSALAccountsProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = B2A3C2872145FD0F0082525C /* MSALAccountsProvider.h */; }; @@ -84,14 +82,10 @@ 04A6B60D226938310035C7C2 /* MSALB2CAuthority.m in Sources */ = {isa = PBXBuildFile; fileRef = 23A68A7920F538B90071E435 /* MSALB2CAuthority.m */; }; 04A6B60E226938330035C7C2 /* MSALADFSAuthority.m in Sources */ = {isa = PBXBuildFile; fileRef = 23A68A7F20F538DE0071E435 /* MSALADFSAuthority.m */; }; 04A6B60F226938340035C7C2 /* MSALADFSAuthority.m in Sources */ = {isa = PBXBuildFile; fileRef = 23A68A7F20F538DE0071E435 /* MSALADFSAuthority.m */; }; - 04A6B610226938360035C7C2 /* MSALAuthorityFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 23A68A8B20F57A440071E435 /* MSALAuthorityFactory.h */; }; - 04A6B611226938370035C7C2 /* MSALAuthorityFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 23A68A8B20F57A440071E435 /* MSALAuthorityFactory.h */; }; - 04A6B612226938390035C7C2 /* MSALAuthorityFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 23A68A8C20F57A440071E435 /* MSALAuthorityFactory.m */; }; - 04A6B6132269383A0035C7C2 /* MSALAuthorityFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 23A68A8C20F57A440071E435 /* MSALAuthorityFactory.m */; }; - 04A6B6142269383C0035C7C2 /* MSALOauth2FactoryProducer.h in Headers */ = {isa = PBXBuildFile; fileRef = B28BDA8C217E9EAB003E5670 /* MSALOauth2FactoryProducer.h */; }; - 04A6B6152269383D0035C7C2 /* MSALOauth2FactoryProducer.h in Headers */ = {isa = PBXBuildFile; fileRef = B28BDA8C217E9EAB003E5670 /* MSALOauth2FactoryProducer.h */; }; - 04A6B6162269383F0035C7C2 /* MSALOauth2FactoryProducer.m in Sources */ = {isa = PBXBuildFile; fileRef = B28BDA8D217E9EAB003E5670 /* MSALOauth2FactoryProducer.m */; }; - 04A6B6172269383F0035C7C2 /* MSALOauth2FactoryProducer.m in Sources */ = {isa = PBXBuildFile; fileRef = B28BDA8D217E9EAB003E5670 /* MSALOauth2FactoryProducer.m */; }; + 04A6B6142269383C0035C7C2 /* MSALOauth2ProviderFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = B28BDA8C217E9EAB003E5670 /* MSALOauth2ProviderFactory.h */; }; + 04A6B6152269383D0035C7C2 /* MSALOauth2ProviderFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = B28BDA8C217E9EAB003E5670 /* MSALOauth2ProviderFactory.h */; }; + 04A6B6162269383F0035C7C2 /* MSALOauth2ProviderFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = B28BDA8D217E9EAB003E5670 /* MSALOauth2ProviderFactory.m */; }; + 04A6B6172269383F0035C7C2 /* MSALOauth2ProviderFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = B28BDA8D217E9EAB003E5670 /* MSALOauth2ProviderFactory.m */; }; 04A6B623226938D20035C7C2 /* libIdentityCore.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D6A206251FC50A4D00755A51 /* libIdentityCore.a */; }; 04A6B624226938EA0035C7C2 /* libIdentityCore.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D6A206231FC50A4D00755A51 /* libIdentityCore.a */; }; 04A6B625226939500035C7C2 /* MSIDTestURLResponse+MSAL.h in Headers */ = {isa = PBXBuildFile; fileRef = 23F32F051FF4787600B2905E /* MSIDTestURLResponse+MSAL.h */; }; @@ -99,12 +93,23 @@ 04D32CAF1FD615B3000B123E /* MSALErrorConverter.m in Sources */ = {isa = PBXBuildFile; fileRef = 04D32CAD1FD615B3000B123E /* MSALErrorConverter.m */; }; 04D32CD01FD8AFF3000B123E /* MSALErrorConverterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 04D32CCF1FD8AFF3000B123E /* MSALErrorConverterTests.m */; }; 04D32CD11FD8AFF3000B123E /* MSALErrorConverterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 04D32CCF1FD8AFF3000B123E /* MSALErrorConverterTests.m */; }; + 1E1A2E042256D12F001009ED /* MSALTestAppSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = D61A64B01E5AAC5C0086D120 /* MSALTestAppSettings.m */; }; + 1E1A2E062256D194001009ED /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E1A2E052256D194001009ED /* AppKit.framework */; }; 1E394C442123812700CC1616 /* MSALTestAppB2CAuthorityViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E394C432123812700CC1616 /* MSALTestAppB2CAuthorityViewController.m */; }; + 1E4522AD22581B8A00D27CA7 /* MSALScopesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E4522AC22581B8A00D27CA7 /* MSALScopesViewController.m */; }; 1E4FD39E2121F2910069BCF6 /* MSALTestAppSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D61A64A81E5AABC50086D120 /* MSALTestAppSettingsViewController.m */; }; + 1E614BDE22558D8300EBF62F /* MSALAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E614BDD22558D8300EBF62F /* MSALAppDelegate.m */; }; + 1E614BE322558D8300EBF62F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1E614BE222558D8300EBF62F /* Assets.xcassets */; }; + 1E614BE622558D8300EBF62F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1E614BE422558D8300EBF62F /* Main.storyboard */; }; + 1E614BE922558D8300EBF62F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E614BE822558D8300EBF62F /* main.m */; }; 1E665DB92162A83E0049A59A /* MSALTestAppProfileViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E665DB82162A83E0049A59A /* MSALTestAppProfileViewController.m */; }; + 1E8B0026225E8019006BB8BD /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96902DF520E1579000200E6F /* WebKit.framework */; }; + 1E8B0031225E94A3006BB8BD /* MSALCacheViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E8B002E225E81A2006BB8BD /* MSALCacheViewController.m */; }; 1E8FC6A3221F370C00B4D4C1 /* MSALResultTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E8FC6A2221F370C00B4D4C1 /* MSALResultTests.m */; }; 1E8FC6A4221F370C00B4D4C1 /* MSALResultTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E8FC6A2221F370C00B4D4C1 /* MSALResultTests.m */; }; 1EB7ABD621262C420058C7E0 /* MSALTestAppAuthorityTypeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EB7ABD521262C420058C7E0 /* MSALTestAppAuthorityTypeViewController.m */; }; + 1EC12C112255DB9200339572 /* MSALAcquireTokenViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EC12C102255DB9200339572 /* MSALAcquireTokenViewController.m */; }; + 1EC12C3A2256BC6800339572 /* MSAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D65A6F501E3FD32D00C69FBA /* MSAL.framework */; }; 1EDAE32C218A4FA0001898E1 /* MSALAuthority_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 23A68A8A20F5508B0071E435 /* MSALAuthority_Internal.h */; }; 1EDAE331218A4FA2001898E1 /* MSALAuthority_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 23A68A8A20F5508B0071E435 /* MSALAuthority_Internal.h */; }; 231CE9DC1FEC682000E95D3E /* libIdentityTest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D6A206271FC50A4D00755A51 /* libIdentityTest.a */; }; @@ -136,12 +141,18 @@ 232D68DE223DBA0700594BBD /* MSALInteractiveTokenParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = 232D68DB223DBA0700594BBD /* MSALInteractiveTokenParameters.m */; }; 232D68DF223DBA0700594BBD /* MSALInteractiveTokenParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = 232D68DB223DBA0700594BBD /* MSALInteractiveTokenParameters.m */; }; 232D69002240A3FF00594BBD /* MSALTokenParameters+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 232D68FF2240A3FF00594BBD /* MSALTokenParameters+Internal.h */; }; + 233E96FD22653EFC007FCE2A /* MSALTelemetryEventsObservingProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 233E96FA22653EFC007FCE2A /* MSALTelemetryEventsObservingProxy.m */; }; + 233E96FE22653EFC007FCE2A /* MSALTelemetryEventsObservingProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 233E96FA22653EFC007FCE2A /* MSALTelemetryEventsObservingProxy.m */; }; + 233E970B226571AB007FCE2A /* MSALTelemetryAggregatedTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 233E970A226571AB007FCE2A /* MSALTelemetryAggregatedTests.m */; }; + 233E970C226571AC007FCE2A /* MSALTelemetryAggregatedTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 233E970A226571AB007FCE2A /* MSALTelemetryAggregatedTests.m */; }; 2342584B20649A9800621AFE /* MSALAccount+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 2342584A20649A9800621AFE /* MSALAccount+Internal.h */; }; 2342584C20649A9800621AFE /* MSALAccount+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 2342584A20649A9800621AFE /* MSALAccount+Internal.h */; }; 23576D402252C07700D6F7BA /* MSALClaimsRequest+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 23576D3F2252C07700D6F7BA /* MSALClaimsRequest+Internal.h */; }; 23576D412252C07700D6F7BA /* MSALClaimsRequest+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 23576D3F2252C07700D6F7BA /* MSALClaimsRequest+Internal.h */; }; 2364C74B1FB3E5CB00835428 /* XCTestCase+HelperMethods.m in Sources */ = {isa = PBXBuildFile; fileRef = 2364C7471FB3E52E00835428 /* XCTestCase+HelperMethods.m */; }; 2364C74C1FB3E5CC00835428 /* XCTestCase+HelperMethods.m in Sources */ = {isa = PBXBuildFile; fileRef = 2364C7471FB3E52E00835428 /* XCTestCase+HelperMethods.m */; }; + 238BA014227BCAED00A5BACD /* MSALTenantProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 6077D49F22498BFF001798A2 /* MSALTenantProfile.h */; }; + 238BA01B227BCAEE00A5BACD /* MSALTenantProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 6077D49F22498BFF001798A2 /* MSALTenantProfile.h */; }; 23A169B420732F3A00B051F3 /* MSALB2CPolicyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B25F1BB21EC257F900474D1B /* MSALB2CPolicyTests.m */; }; 23A169B52073325500B051F3 /* MSALPublicClientApplicationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D673F07C1E4AAB0D0018BA91 /* MSALPublicClientApplicationTests.m */; }; 23A68A7520F5386A0071E435 /* MSALAADAuthority.h in Headers */ = {isa = PBXBuildFile; fileRef = 23A68A7220F5386A0071E435 /* MSALAADAuthority.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -153,16 +164,16 @@ 23A68A8120F538DE0071E435 /* MSALADFSAuthority.h in Headers */ = {isa = PBXBuildFile; fileRef = 23A68A7E20F538DE0071E435 /* MSALADFSAuthority.h */; settings = {ATTRIBUTES = (Public, ); }; }; 23A68A8220F538DE0071E435 /* MSALADFSAuthority.m in Sources */ = {isa = PBXBuildFile; fileRef = 23A68A7F20F538DE0071E435 /* MSALADFSAuthority.m */; }; 23A68A8320F538DE0071E435 /* MSALADFSAuthority.m in Sources */ = {isa = PBXBuildFile; fileRef = 23A68A7F20F538DE0071E435 /* MSALADFSAuthority.m */; }; - 23A68A8D20F57A440071E435 /* MSALAuthorityFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 23A68A8B20F57A440071E435 /* MSALAuthorityFactory.h */; }; - 23A68A8E20F57A440071E435 /* MSALAuthorityFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 23A68A8B20F57A440071E435 /* MSALAuthorityFactory.h */; }; - 23A68A8F20F57A440071E435 /* MSALAuthorityFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 23A68A8C20F57A440071E435 /* MSALAuthorityFactory.m */; }; - 23A68A9020F57A440071E435 /* MSALAuthorityFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 23A68A8C20F57A440071E435 /* MSALAuthorityFactory.m */; }; 23A68A9320F59E6B0071E435 /* NSString+MSALTestUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 23A68A9220F59E6B0071E435 /* NSString+MSALTestUtil.m */; }; 23A68A9420F59E6B0071E435 /* NSString+MSALTestUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 23A68A9220F59E6B0071E435 /* NSString+MSALTestUtil.m */; }; - 23CDA9B31FA45A9E00FDD5C0 /* MSALTelemetryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 23CDA9B01FA4443800FDD5C0 /* MSALTelemetryTests.m */; }; 23F32F0C1FF4789100B2905E /* MSIDTestURLResponse+MSAL.m in Sources */ = {isa = PBXBuildFile; fileRef = 23F32F061FF4787600B2905E /* MSIDTestURLResponse+MSAL.m */; }; 23F32F0D1FF4789200B2905E /* MSIDTestURLResponse+MSAL.m in Sources */ = {isa = PBXBuildFile; fileRef = 23F32F061FF4787600B2905E /* MSIDTestURLResponse+MSAL.m */; }; 23FB5C1E22542B99002BF1EB /* MSALJsonDeserializable.h in Headers */ = {isa = PBXBuildFile; fileRef = 23FB5C1C22542B99002BF1EB /* MSALJsonDeserializable.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6077D4A022498BFF001798A2 /* MSALTenantProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 6077D49F22498BFF001798A2 /* MSALTenantProfile.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6077D4A122498BFF001798A2 /* MSALTenantProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 6077D49F22498BFF001798A2 /* MSALTenantProfile.h */; }; + 6077D4A922498D87001798A2 /* MSALTenantProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = 6077D4A822498D87001798A2 /* MSALTenantProfile.m */; }; + 6077D4AA22498D87001798A2 /* MSALTenantProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = 6077D4A822498D87001798A2 /* MSALTenantProfile.m */; }; + 609AF9332256BD0C00E2978D /* MSALAccountsProviderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 609AF9322256BD0C00E2978D /* MSALAccountsProviderTests.m */; }; 94E876CE1E492D6000FB96ED /* MSALAuthority.m in Sources */ = {isa = PBXBuildFile; fileRef = 94E876CB1E492D6000FB96ED /* MSALAuthority.m */; }; 960751BB2183E82C00F2BF2F /* MSALAccountIdTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 960751BA2183E82C00F2BF2F /* MSALAccountIdTests.m */; }; 960751BC2183E82C00F2BF2F /* MSALAccountIdTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 960751BA2183E82C00F2BF2F /* MSALAccountIdTests.m */; }; @@ -270,6 +281,16 @@ B221CEDE20C0AC60002F5E94 /* MSALAccountId.m in Sources */ = {isa = PBXBuildFile; fileRef = B221CEDA20C0AC60002F5E94 /* MSALAccountId.m */; }; B221CEEB20C0AF0B002F5E94 /* MSALAccountId+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = B221CEEA20C0AF0B002F5E94 /* MSALAccountId+Internal.h */; }; B221CEEC20C0AF0B002F5E94 /* MSALAccountId+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = B221CEEA20C0AF0B002F5E94 /* MSALAccountId+Internal.h */; }; + B223B0B322ADF8C500FB8713 /* MSALLegacySharedADALAccount.h in Headers */ = {isa = PBXBuildFile; fileRef = B223B0B122ADF8C500FB8713 /* MSALLegacySharedADALAccount.h */; }; + B223B0B522ADF8C500FB8713 /* MSALLegacySharedADALAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = B223B0B222ADF8C500FB8713 /* MSALLegacySharedADALAccount.m */; }; + B223B0B922ADF8E600FB8713 /* MSALLegacySharedMSAAccount.h in Headers */ = {isa = PBXBuildFile; fileRef = B223B0B722ADF8E600FB8713 /* MSALLegacySharedMSAAccount.h */; }; + B223B0BA22ADF8E600FB8713 /* MSALLegacySharedMSAAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = B223B0B822ADF8E600FB8713 /* MSALLegacySharedMSAAccount.m */; }; + B223B0BF22ADFACB00FB8713 /* MSALLegacySharedAccount.h in Headers */ = {isa = PBXBuildFile; fileRef = B223B0BD22ADFACB00FB8713 /* MSALLegacySharedAccount.h */; }; + B223B0C022ADFACB00FB8713 /* MSALLegacySharedAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = B223B0BE22ADFACB00FB8713 /* MSALLegacySharedAccount.m */; }; + B223B0C522AE215D00FB8713 /* MSALLegacySharedAccountFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = B223B0C322AE215D00FB8713 /* MSALLegacySharedAccountFactory.h */; }; + B223B0C622AE215D00FB8713 /* MSALLegacySharedAccountFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = B223B0C422AE215D00FB8713 /* MSALLegacySharedAccountFactory.m */; }; + B227037122A4BA3600030ADC /* MSALLegacySharedAccountsProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = B29A56BD228266E20023F5E6 /* MSALLegacySharedAccountsProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B227037322A4BA3E00030ADC /* MSALLegacySharedAccountsProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = B29A56BE228266E20023F5E6 /* MSALLegacySharedAccountsProvider.m */; }; B2472CA3226FDC46008F22AB /* MSALB2CAuthority_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = B2472CA2226FDC46008F22AB /* MSALB2CAuthority_Internal.h */; }; B2472CA4226FDC46008F22AB /* MSALB2CAuthority_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = B2472CA2226FDC46008F22AB /* MSALB2CAuthority_Internal.h */; }; B2472CA5226FDC46008F22AB /* MSALB2CAuthority_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = B2472CA2226FDC46008F22AB /* MSALB2CAuthority_Internal.h */; }; @@ -288,14 +309,54 @@ B25F1BBB1EC3DB3200474D1B /* MSIDTokenCacheItem+Automation.m in Sources */ = {isa = PBXBuildFile; fileRef = B25F1BBA1EC3DB3200474D1B /* MSIDTokenCacheItem+Automation.m */; }; B25F1BC11EC3DD3200474D1B /* MSALUser+Automation.m in Sources */ = {isa = PBXBuildFile; fileRef = B25F1BC01EC3DD3200474D1B /* MSALUser+Automation.m */; }; B25F1BC41EC3E44500474D1B /* MSALResult+Automation.m in Sources */ = {isa = PBXBuildFile; fileRef = B25F1BC31EC3E44500474D1B /* MSALResult+Automation.m */; }; + B2659C872287D13B00F5A0C3 /* MSALSerializedADALCacheProvider+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = B2659C862287D13B00F5A0C3 /* MSALSerializedADALCacheProvider+Internal.h */; }; + B2659C882287D13B00F5A0C3 /* MSALSerializedADALCacheProvider+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = B2659C862287D13B00F5A0C3 /* MSALSerializedADALCacheProvider+Internal.h */; }; + B266391B22B4B84600FEB673 /* NSString+MSALAccountIdenfiers.h in Headers */ = {isa = PBXBuildFile; fileRef = B266391922B4B84600FEB673 /* NSString+MSALAccountIdenfiers.h */; }; + B266391C22B4B84600FEB673 /* NSString+MSALAccountIdenfiers.m in Sources */ = {isa = PBXBuildFile; fileRef = B266391A22B4B84600FEB673 /* NSString+MSALAccountIdenfiers.m */; }; + B267569D228F335E000F01D7 /* MSALExternalAccountHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = B267569B228F335E000F01D7 /* MSALExternalAccountHandler.h */; }; + B267569E228F335E000F01D7 /* MSALExternalAccountHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = B267569B228F335E000F01D7 /* MSALExternalAccountHandler.h */; }; + B267569F228F335E000F01D7 /* MSALExternalAccountHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = B267569C228F335E000F01D7 /* MSALExternalAccountHandler.m */; }; + B26756A0228F335E000F01D7 /* MSALExternalAccountHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = B267569C228F335E000F01D7 /* MSALExternalAccountHandler.m */; }; + B26756BE22921A71000F01D7 /* MSALOauth2Provider.h in Headers */ = {isa = PBXBuildFile; fileRef = B26756BC22921A71000F01D7 /* MSALOauth2Provider.h */; }; + B26756BF22921A71000F01D7 /* MSALOauth2Provider.h in Headers */ = {isa = PBXBuildFile; fileRef = B26756BC22921A71000F01D7 /* MSALOauth2Provider.h */; }; + B26756C022921A71000F01D7 /* MSALOauth2Provider.m in Sources */ = {isa = PBXBuildFile; fileRef = B26756BD22921A71000F01D7 /* MSALOauth2Provider.m */; }; + B26756C122921A71000F01D7 /* MSALOauth2Provider.m in Sources */ = {isa = PBXBuildFile; fileRef = B26756BD22921A71000F01D7 /* MSALOauth2Provider.m */; }; + B26756C422921C42000F01D7 /* MSALAADOauth2Provider.h in Headers */ = {isa = PBXBuildFile; fileRef = B26756C222921C42000F01D7 /* MSALAADOauth2Provider.h */; }; + B26756C522921C42000F01D7 /* MSALAADOauth2Provider.h in Headers */ = {isa = PBXBuildFile; fileRef = B26756C222921C42000F01D7 /* MSALAADOauth2Provider.h */; }; + B26756C622921C42000F01D7 /* MSALAADOauth2Provider.m in Sources */ = {isa = PBXBuildFile; fileRef = B26756C322921C42000F01D7 /* MSALAADOauth2Provider.m */; }; + B26756C722921C42000F01D7 /* MSALAADOauth2Provider.m in Sources */ = {isa = PBXBuildFile; fileRef = B26756C322921C42000F01D7 /* MSALAADOauth2Provider.m */; }; + B26756CA22921C5B000F01D7 /* MSALB2COauth2Provider.h in Headers */ = {isa = PBXBuildFile; fileRef = B26756C822921C5B000F01D7 /* MSALB2COauth2Provider.h */; }; + B26756CB22921C5B000F01D7 /* MSALB2COauth2Provider.h in Headers */ = {isa = PBXBuildFile; fileRef = B26756C822921C5B000F01D7 /* MSALB2COauth2Provider.h */; }; + B26756CC22921C5B000F01D7 /* MSALB2COauth2Provider.m in Sources */ = {isa = PBXBuildFile; fileRef = B26756C922921C5B000F01D7 /* MSALB2COauth2Provider.m */; }; + B26756CD22921C5B000F01D7 /* MSALB2COauth2Provider.m in Sources */ = {isa = PBXBuildFile; fileRef = B26756C922921C5B000F01D7 /* MSALB2COauth2Provider.m */; }; + B26756D022921C6D000F01D7 /* MSALADFSOauth2Provider.h in Headers */ = {isa = PBXBuildFile; fileRef = B26756CE22921C6D000F01D7 /* MSALADFSOauth2Provider.h */; }; + B26756D122921C6D000F01D7 /* MSALADFSOauth2Provider.h in Headers */ = {isa = PBXBuildFile; fileRef = B26756CE22921C6D000F01D7 /* MSALADFSOauth2Provider.h */; }; + B26756D222921C6D000F01D7 /* MSALADFSOauth2Provider.m in Sources */ = {isa = PBXBuildFile; fileRef = B26756CF22921C6D000F01D7 /* MSALADFSOauth2Provider.m */; }; + B26756D322921C6D000F01D7 /* MSALADFSOauth2Provider.m in Sources */ = {isa = PBXBuildFile; fileRef = B26756CF22921C6D000F01D7 /* MSALADFSOauth2Provider.m */; }; + B26756D522921CC4000F01D7 /* MSALOauth2Provider+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = B26756D422921CC4000F01D7 /* MSALOauth2Provider+Internal.h */; }; + B26756D622921CC4000F01D7 /* MSALOauth2Provider+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = B26756D422921CC4000F01D7 /* MSALOauth2Provider+Internal.h */; }; + B26756D922922375000F01D7 /* MSALOauth2Authority.h in Headers */ = {isa = PBXBuildFile; fileRef = B26756D722922375000F01D7 /* MSALOauth2Authority.h */; }; + B26756DA22922375000F01D7 /* MSALOauth2Authority.h in Headers */ = {isa = PBXBuildFile; fileRef = B26756D722922375000F01D7 /* MSALOauth2Authority.h */; }; + B26756DB22922375000F01D7 /* MSALOauth2Authority.m in Sources */ = {isa = PBXBuildFile; fileRef = B26756D822922375000F01D7 /* MSALOauth2Authority.m */; }; + B26756DC22922375000F01D7 /* MSALOauth2Authority.m in Sources */ = {isa = PBXBuildFile; fileRef = B26756D822922375000F01D7 /* MSALOauth2Authority.m */; }; + B2725E7F22BD88BE009B454A /* NSStringAccountIdentifiersTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B2725E7E22BD88BE009B454A /* NSStringAccountIdentifiersTest.m */; }; + B2725EAC22BF2759009B454A /* MSALExternalAccountHandlerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B2725EAB22BF2759009B454A /* MSALExternalAccountHandlerTests.m */; }; + B2725EAD22BF2759009B454A /* MSALExternalAccountHandlerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B2725EAB22BF2759009B454A /* MSALExternalAccountHandlerTests.m */; }; + B2725EB522BF2774009B454A /* MSALPublicClientApplicationAccountUpdateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B2725EB422BF2774009B454A /* MSALPublicClientApplicationAccountUpdateTests.m */; }; + B2725EB622BF2774009B454A /* MSALPublicClientApplicationAccountUpdateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B2725EB422BF2774009B454A /* MSALPublicClientApplicationAccountUpdateTests.m */; }; + B2725EC522BF4865009B454A /* MSALMockExternalAccountHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = B2725EB822BF27FF009B454A /* MSALMockExternalAccountHandler.m */; }; + B2725EC622BF4865009B454A /* MSALMockExternalAccountHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = B2725EB822BF27FF009B454A /* MSALMockExternalAccountHandler.m */; }; + B2725ECA22C04661009B454A /* MSALLegacySharedAccountTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B2725EC922C04661009B454A /* MSALLegacySharedAccountTests.m */; }; + B2725ECC22C0466E009B454A /* MSALLegacySharedADALAccountTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B2725ECB22C0466E009B454A /* MSALLegacySharedADALAccountTests.m */; }; + B2725ECE22C04679009B454A /* MSALLegacySharedMSAAccountTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B2725ECD22C04679009B454A /* MSALLegacySharedMSAAccountTests.m */; }; + B2725ED022C04689009B454A /* MSALLegacySharedAccountFactoryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B2725ECF22C04689009B454A /* MSALLegacySharedAccountFactoryTests.m */; }; + B2725ED222C0469A009B454A /* MSALLegacySharedAccountsProviderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B2725ED122C0469A009B454A /* MSALLegacySharedAccountsProviderTests.m */; }; B273D067226E84BD005A7BB4 /* MSALPublicClientApplicationConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 9627C7AB22542EDC0028A859 /* MSALPublicClientApplicationConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; B273D06E226E84BD005A7BB4 /* MSALPublicClientApplicationConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 9627C7AB22542EDC0028A859 /* MSALPublicClientApplicationConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; B273D06F226E84C3005A7BB4 /* MSALGlobalConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 9626D14A225828780019417B /* MSALGlobalConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; B273D070226E84C3005A7BB4 /* MSALGlobalConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 9626D14A225828780019417B /* MSALGlobalConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; B273D071226E84C9005A7BB4 /* MSALSliceConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 96B5E6EA2256D180002232F9 /* MSALSliceConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; B273D072226E84CA005A7BB4 /* MSALSliceConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 96B5E6EA2256D180002232F9 /* MSALSliceConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; - B273D073226E84CF005A7BB4 /* MSALCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 96B5E6CC2256D152002232F9 /* MSALCacheConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; - B273D074226E84CF005A7BB4 /* MSALCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 96B5E6CC2256D152002232F9 /* MSALCacheConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; B273D075226E84D6005A7BB4 /* MSALTelemetryConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 96B5E6DE2256D166002232F9 /* MSALTelemetryConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; B273D076226E84D6005A7BB4 /* MSALTelemetryConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 96B5E6DE2256D166002232F9 /* MSALTelemetryConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; B273D077226E84DD005A7BB4 /* MSALHTTPConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 96B5E6D82256D15A002232F9 /* MSALHTTPConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -324,10 +385,6 @@ B273D08E226E852F005A7BB4 /* MSALJsonSerializable.h in Headers */ = {isa = PBXBuildFile; fileRef = 232D616922498EDF00260C42 /* MSALJsonSerializable.h */; settings = {ATTRIBUTES = (Public, ); }; }; B273D08F226E8534005A7BB4 /* MSALJsonDeserializable.h in Headers */ = {isa = PBXBuildFile; fileRef = 23FB5C1C22542B99002BF1EB /* MSALJsonDeserializable.h */; settings = {ATTRIBUTES = (Public, ); }; }; B273D090226E8534005A7BB4 /* MSALJsonDeserializable.h in Headers */ = {isa = PBXBuildFile; fileRef = 23FB5C1C22542B99002BF1EB /* MSALJsonDeserializable.h */; settings = {ATTRIBUTES = (Public, ); }; }; - B273D091226E854C005A7BB4 /* MSALDefaultDispatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = E02396D11E776F10004D6278 /* MSALDefaultDispatcher.h */; }; - B273D092226E854C005A7BB4 /* MSALDefaultDispatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = E02396D11E776F10004D6278 /* MSALDefaultDispatcher.h */; }; - B273D093226E854D005A7BB4 /* MSALDefaultDispatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = E02396D11E776F10004D6278 /* MSALDefaultDispatcher.h */; }; - B273D094226E854E005A7BB4 /* MSALDefaultDispatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = E02396D11E776F10004D6278 /* MSALDefaultDispatcher.h */; }; B273D095226E855B005A7BB4 /* MSALRedirectUri.m in Sources */ = {isa = PBXBuildFile; fileRef = B203459321AF77FB00B221AA /* MSALRedirectUri.m */; }; B273D096226E855C005A7BB4 /* MSALRedirectUri.m in Sources */ = {isa = PBXBuildFile; fileRef = B203459321AF77FB00B221AA /* MSALRedirectUri.m */; }; B273D097226E855E005A7BB4 /* MSALRedirectUri+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = B203459C21AFA1FB00B221AA /* MSALRedirectUri+Internal.h */; }; @@ -426,15 +483,35 @@ B273D0F5226E86C1005A7BB4 /* MSALAuthority_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 23A68A8A20F5508B0071E435 /* MSALAuthority_Internal.h */; }; B273D0F6226E86C2005A7BB4 /* MSALAuthority_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 23A68A8A20F5508B0071E435 /* MSALAuthority_Internal.h */; }; B277241E1EAE97D700375C53 /* MSALStressTestHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = B277241D1EAE97D700375C53 /* MSALStressTestHelper.m */; }; + B27CCDE0229F65D700CAD565 /* MSALAccount+MultiTenantAccount.h in Headers */ = {isa = PBXBuildFile; fileRef = B27CCDDE229F65D700CAD565 /* MSALAccount+MultiTenantAccount.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B27CCDE1229F65D700CAD565 /* MSALAccount+MultiTenantAccount.h in Headers */ = {isa = PBXBuildFile; fileRef = B27CCDDE229F65D700CAD565 /* MSALAccount+MultiTenantAccount.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B27CCDF2229F9F4700CAD565 /* MSALAccountEnumerationParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = B27CCDF0229F9F4700CAD565 /* MSALAccountEnumerationParameters.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B27CCDF3229F9F4700CAD565 /* MSALAccountEnumerationParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = B27CCDF0229F9F4700CAD565 /* MSALAccountEnumerationParameters.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B27CCDF4229F9F4700CAD565 /* MSALAccountEnumerationParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = B27CCDF1229F9F4700CAD565 /* MSALAccountEnumerationParameters.m */; }; + B27CCDF5229F9F4700CAD565 /* MSALAccountEnumerationParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = B27CCDF1229F9F4700CAD565 /* MSALAccountEnumerationParameters.m */; }; B281B33B226BC225009619AB /* MSALPublicClientApplicationConfigTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B281B33A226BC225009619AB /* MSALPublicClientApplicationConfigTests.m */; }; B281B33C226BC225009619AB /* MSALPublicClientApplicationConfigTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B281B33A226BC225009619AB /* MSALPublicClientApplicationConfigTests.m */; }; B28BBD342211DC7D00F51723 /* MSALPublicClientStatusNotifications.h in Headers */ = {isa = PBXBuildFile; fileRef = B28BBD312211DC7D00F51723 /* MSALPublicClientStatusNotifications.h */; settings = {ATTRIBUTES = (Public, ); }; }; B28BBD352211DC7D00F51723 /* MSALPublicClientStatusNotifications.m in Sources */ = {isa = PBXBuildFile; fileRef = B28BBD322211DC7D00F51723 /* MSALPublicClientStatusNotifications.m */; }; B28BBD362211DC7D00F51723 /* MSALPublicClientStatusNotifications.m in Sources */ = {isa = PBXBuildFile; fileRef = B28BBD322211DC7D00F51723 /* MSALPublicClientStatusNotifications.m */; }; - B28BDA8E217E9EAB003E5670 /* MSALOauth2FactoryProducer.h in Headers */ = {isa = PBXBuildFile; fileRef = B28BDA8C217E9EAB003E5670 /* MSALOauth2FactoryProducer.h */; }; - B28BDA8F217E9EAB003E5670 /* MSALOauth2FactoryProducer.h in Headers */ = {isa = PBXBuildFile; fileRef = B28BDA8C217E9EAB003E5670 /* MSALOauth2FactoryProducer.h */; }; - B28BDA90217E9EAB003E5670 /* MSALOauth2FactoryProducer.m in Sources */ = {isa = PBXBuildFile; fileRef = B28BDA8D217E9EAB003E5670 /* MSALOauth2FactoryProducer.m */; }; - B28BDA91217E9EAB003E5670 /* MSALOauth2FactoryProducer.m in Sources */ = {isa = PBXBuildFile; fileRef = B28BDA8D217E9EAB003E5670 /* MSALOauth2FactoryProducer.m */; }; + B28BDA8E217E9EAB003E5670 /* MSALOauth2ProviderFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = B28BDA8C217E9EAB003E5670 /* MSALOauth2ProviderFactory.h */; }; + B28BDA8F217E9EAB003E5670 /* MSALOauth2ProviderFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = B28BDA8C217E9EAB003E5670 /* MSALOauth2ProviderFactory.h */; }; + B28BDA90217E9EAB003E5670 /* MSALOauth2ProviderFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = B28BDA8D217E9EAB003E5670 /* MSALOauth2ProviderFactory.m */; }; + B28BDA91217E9EAB003E5670 /* MSALOauth2ProviderFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = B28BDA8D217E9EAB003E5670 /* MSALOauth2ProviderFactory.m */; }; + B295A16822D0348400FFB313 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B295A16722D0348400FFB313 /* AppDelegate.m */; }; + B295A16B22D0348400FFB313 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B295A16A22D0348400FFB313 /* ViewController.m */; }; + B295A16D22D0348600FFB313 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B295A16C22D0348600FFB313 /* Assets.xcassets */; }; + B295A17022D0348600FFB313 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B295A16E22D0348600FFB313 /* Main.storyboard */; }; + B295A17322D0348600FFB313 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B295A17222D0348600FFB313 /* main.m */; }; + B295A17A22D0352600FFB313 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E1A2E052256D194001009ED /* AppKit.framework */; }; + B29A56A5228262770023F5E6 /* MSALExternalAccountProviding.h in Headers */ = {isa = PBXBuildFile; fileRef = B29A56A4228262770023F5E6 /* MSALExternalAccountProviding.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B29A56A6228262770023F5E6 /* MSALExternalAccountProviding.h in Headers */ = {isa = PBXBuildFile; fileRef = B29A56A4228262770023F5E6 /* MSALExternalAccountProviding.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B29A56BA228266B40023F5E6 /* MSALSerializedADALCacheProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = B29A56B8228266B40023F5E6 /* MSALSerializedADALCacheProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B29A56BB228266B40023F5E6 /* MSALSerializedADALCacheProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = B29A56B9228266B40023F5E6 /* MSALSerializedADALCacheProvider.m */; }; + B29A56C122826EE00023F5E6 /* MSALSerializedADALCacheProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = B29A56B8228266B40023F5E6 /* MSALSerializedADALCacheProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B29A56C222826EE20023F5E6 /* MSALSerializedADALCacheProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = B29A56B9228266B40023F5E6 /* MSALSerializedADALCacheProvider.m */; }; + B29A56D52283D7430023F5E6 /* MSALAADAuthorityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B29A56CE2283D7430023F5E6 /* MSALAADAuthorityTests.m */; }; + B29A56D62283D7430023F5E6 /* MSALAADAuthorityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B29A56CE2283D7430023F5E6 /* MSALAADAuthorityTests.m */; }; B29E2AC321238DFC00B170ED /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96902DEC20E1574F00200E6F /* WebKit.framework */; }; B29E2AC521238E0000B170ED /* SafariServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B29E2AC421238E0000B170ED /* SafariServices.framework */; }; B29E2ADB21238F7F00B170ED /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96902DEC20E1574F00200E6F /* WebKit.framework */; }; @@ -456,11 +533,7 @@ B2A3C28C2145FD0F0082525C /* MSALAccountsProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = B2A3C2882145FD0F0082525C /* MSALAccountsProvider.m */; }; B2A3C29721460D290082525C /* MSALAuthority.h in Headers */ = {isa = PBXBuildFile; fileRef = 94E876CA1E492D6000FB96ED /* MSALAuthority.h */; settings = {ATTRIBUTES = (Public, ); }; }; B2AD634A1EA5663800EFEEF1 /* MSALTestAppTelemetryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B2AD63491EA5663800EFEEF1 /* MSALTestAppTelemetryViewController.m */; }; - B2AD634D1EA5665F00EFEEF1 /* MSALTestAppTelemetryDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = B2AD634C1EA5665F00EFEEF1 /* MSALTestAppTelemetryDispatcher.m */; }; - B2B5F08B1FCA61EB00F6AFAD /* MSALTelemetryDefaultEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = B2B5F0891FCA61EB00F6AFAD /* MSALTelemetryDefaultEvent.h */; }; - B2B5F08C1FCA61EB00F6AFAD /* MSALTelemetryDefaultEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = B2B5F0891FCA61EB00F6AFAD /* MSALTelemetryDefaultEvent.h */; }; - B2B5F08D1FCA61EB00F6AFAD /* MSALTelemetryDefaultEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = B2B5F08A1FCA61EB00F6AFAD /* MSALTelemetryDefaultEvent.m */; }; - B2B5F08E1FCA61EB00F6AFAD /* MSALTelemetryDefaultEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = B2B5F08A1FCA61EB00F6AFAD /* MSALTelemetryDefaultEvent.m */; }; + B2ADD76E22C08B6A0093FD43 /* MSALLegacySharedAccountTestUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B2ADD76D22C08B6A0093FD43 /* MSALLegacySharedAccountTestUtil.m */; }; B2BB73732112C32C000EA4C5 /* MSALAADBasicInteractiveTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B2BB73722112C32C000EA4C5 /* MSALAADBasicInteractiveTests.m */; }; B2BB738D2112C3F3000EA4C5 /* MSALBaseiOSUITest.m in Sources */ = {isa = PBXBuildFile; fileRef = B2BB73812112C3F1000EA4C5 /* MSALBaseiOSUITest.m */; }; B2BB738E2112C3F3000EA4C5 /* XCTestCase+TextFieldTap.m in Sources */ = {isa = PBXBuildFile; fileRef = B2BB73842112C3F2000EA4C5 /* XCTestCase+TextFieldTap.m */; }; @@ -491,14 +564,11 @@ B2FE601B20E5BB5800502BA6 /* MSAL.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D65A6F431E3FD30A00C69FBA /* MSAL.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; D61A64941E5AA7D60086D120 /* MSALTestAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D61A64801E5AA7C60086D120 /* MSALTestAppDelegate.m */; }; D61A64951E5AA7D60086D120 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D61A64811E5AA7C60086D120 /* main.m */; }; - D61A64971E5AA7E20086D120 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D61A648C1E5AA7C60086D120 /* main.m */; }; - D61A64981E5AA7E20086D120 /* MSALTestAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D61A648E1E5AA7C60086D120 /* MSALTestAppDelegate.m */; }; D61A64A91E5AABC50086D120 /* MSALTestAppAcquireTokenViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D61A649D1E5AABC50086D120 /* MSALTestAppAcquireTokenViewController.m */; }; D61A64AA1E5AABC50086D120 /* MSALTestAppAcquireLayoutBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = D61A649F1E5AABC50086D120 /* MSALTestAppAcquireLayoutBuilder.m */; }; D61A64AB1E5AABC50086D120 /* MSALTestAppCacheViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D61A64A21E5AABC50086D120 /* MSALTestAppCacheViewController.m */; }; D61A64AC1E5AABC50086D120 /* MSALTestAppLogViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D61A64A41E5AABC50086D120 /* MSALTestAppLogViewController.m */; }; D61A64B11E5AAC5C0086D120 /* MSALTestAppSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = D61A64B01E5AAC5C0086D120 /* MSALTestAppSettings.m */; }; - D61A64B21E5AAC5C0086D120 /* MSALTestAppSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = D61A64B01E5AAC5C0086D120 /* MSALTestAppSettings.m */; }; D61A64B91E5ADBE80086D120 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D61A64B81E5ADBE80086D120 /* Images.xcassets */; }; D61BD2AD1EBD09F90007E484 /* MSALError.m in Sources */ = {isa = PBXBuildFile; fileRef = D65A6F741E3FF3D900C69FBA /* MSALError.m */; }; D61BD2AF1EBD09F90007E484 /* MSALLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = D65A6F771E3FF3D900C69FBA /* MSALLogger.m */; }; @@ -507,7 +577,6 @@ D61BD2B21EBD09F90007E484 /* MSALAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = D65A6F7A1E3FF3D900C69FBA /* MSALAccount.m */; }; D61BD2B31EBD09F90007E484 /* MSALPromptType.m in Sources */ = {isa = PBXBuildFile; fileRef = D69ADB1A1E50531300952049 /* MSALPromptType.m */; }; D61BD2BD1EBD0A010007E484 /* MSALTelemetry.m in Sources */ = {isa = PBXBuildFile; fileRef = 96D9A5471E4AB22900674A85 /* MSALTelemetry.m */; }; - D61BD2BF1EBD0A010007E484 /* MSALDefaultDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = E02396D21E776F10004D6278 /* MSALDefaultDispatcher.m */; }; D61BD2C91EBD0A0F0007E484 /* MSALAuthority.m in Sources */ = {isa = PBXBuildFile; fileRef = 94E876CB1E492D6000FB96ED /* MSALAuthority.m */; }; D61F5BC01E5913BE00912CB8 /* SFSafariViewController+TestOverrides.m in Sources */ = {isa = PBXBuildFile; fileRef = D61F5BBF1E5913BE00912CB8 /* SFSafariViewController+TestOverrides.m */; }; D61F5BC31E59193500912CB8 /* MSALFakeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D61F5BC21E59193500912CB8 /* MSALFakeViewController.m */; }; @@ -515,9 +584,8 @@ D61F5BCA1E59359900912CB8 /* MSALFramework.m in Sources */ = {isa = PBXBuildFile; fileRef = D61F5BC91E59359900912CB8 /* MSALFramework.m */; }; D61F5BCB1E59359900912CB8 /* MSALFramework.m in Sources */ = {isa = PBXBuildFile; fileRef = D61F5BC91E59359900912CB8 /* MSALFramework.m */; }; D62746D31E9B38AF00EFCE99 /* MSALPublicClientApplication+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = D62746D11E9B38AF00EFCE99 /* MSALPublicClientApplication+Internal.h */; }; - D62746D91E9B5F1E00EFCE99 /* MSALUserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D62746D81E9B5F1E00EFCE99 /* MSALUserTests.m */; }; - D62746DA1E9B5F1E00EFCE99 /* MSALUserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D62746D81E9B5F1E00EFCE99 /* MSALUserTests.m */; }; - D62B8FD41E6789DD009D6E7E /* MSAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D65A6F501E3FD32D00C69FBA /* MSAL.framework */; }; + D62746D91E9B5F1E00EFCE99 /* MSALAccountTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D62746D81E9B5F1E00EFCE99 /* MSALAccountTests.m */; }; + D62746DA1E9B5F1E00EFCE99 /* MSALAccountTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D62746D81E9B5F1E00EFCE99 /* MSALAccountTests.m */; }; D659D4E41E5EBB49007FBCF7 /* MSALTestAppUserViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D659D4E31E5EBB49007FBCF7 /* MSALTestAppUserViewController.m */; }; D659D4EF1E64BEA3007FBCF7 /* MSALTestAppSettingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D659D4EE1E64BEA3007FBCF7 /* MSALTestAppSettingViewController.m */; }; D65A6FA31E3FF3D900C69FBA /* MSALAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = D65A6F7A1E3FF3D900C69FBA /* MSALAccount.m */; }; @@ -563,11 +631,7 @@ D6A2063E1FC511EB00755A51 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6A206311FC5108000755A51 /* UIKit.framework */; }; D6A2063F1FC512EF00755A51 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6A206311FC5108000755A51 /* UIKit.framework */; }; D6A206401FC512F400755A51 /* SafariServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6A206331FC5109400755A51 /* SafariServices.framework */; }; - D6A206411FC514CE00755A51 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6A206351FC510A400755A51 /* Cocoa.framework */; }; D6B58A541EB2C4A8000B3A5F /* MSALAcquireTokenTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D6B58A531EB2C4A8000B3A5F /* MSALAcquireTokenTests.m */; }; - E02396FB1E7B005C004D6278 /* MSALTelemetryTestDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = E02396F91E7B005C004D6278 /* MSALTelemetryTestDispatcher.m */; }; - E02396FD1E7B0E20004D6278 /* MSALTelemetryDispatcherTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E02396FC1E7B0E20004D6278 /* MSALTelemetryDispatcherTests.m */; }; - E023970B1E7B1C4B004D6278 /* MSALDefaultDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = E02396D21E776F10004D6278 /* MSALDefaultDispatcher.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -585,6 +649,13 @@ remoteGlobalIDString = D626FF5A1FBA6E9500EE4487; remoteInfo = "IdentityCore Mac"; }; + 1EC12C382256BC5400339572 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D6DFF39A1E2579360012891A /* Project object */; + proxyType = 1; + remoteGlobalIDString = D65A6F4F1E3FD32D00C69FBA; + remoteInfo = "MSAL (Mac Framework)"; + }; 231CE9D21FEC641D00E95D3E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D6A206191FC50A4D00755A51 /* IdentityCore.xcodeproj */; @@ -648,6 +719,13 @@ remoteGlobalIDString = B27551D520817A1E00AA7A38; remoteInfo = "IdentityAutomation Mac"; }; + B295A17822D034F400FFB313 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D6DFF39A1E2579360012891A /* Project object */; + proxyType = 1; + remoteGlobalIDString = B295A16322D0348400FFB313; + remoteInfo = "unit-test-host-mac"; + }; B29E2AD321238F5200B170ED /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D6DFF39A1E2579360012891A /* Project object */; @@ -815,20 +893,35 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 04A6B57B226921890035C7C2 /* libMSAL.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMSAL.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 04A6B57B226921890035C7C2 /* libMSAL.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = libMSAL.a; path = "libMSAL (iOS Static Library).a"; sourceTree = BUILT_PRODUCTS_DIR; }; 04A6B584226921CD0035C7C2 /* msal__static__lib__ios.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = msal__static__lib__ios.xcconfig; sourceTree = ""; }; 04A6B585226921CD0035C7C2 /* msal__static__lib__mac.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = msal__static__lib__mac.xcconfig; sourceTree = ""; }; - 04A6B59C2269286F0035C7C2 /* libMSAL.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMSAL.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 04A6B59C2269286F0035C7C2 /* libMSAL.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = libMSAL.a; path = "libMSAL (macOS Static Library).a"; sourceTree = BUILT_PRODUCTS_DIR; }; 04D32CAC1FD61585000B123E /* MSALErrorConverter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALErrorConverter.h; sourceTree = ""; }; 04D32CAD1FD615B3000B123E /* MSALErrorConverter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALErrorConverter.m; sourceTree = ""; }; 04D32CCF1FD8AFF3000B123E /* MSALErrorConverterTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALErrorConverterTests.m; sourceTree = ""; }; + 1E1A2E052256D194001009ED /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 1E394C422123812700CC1616 /* MSALTestAppB2CAuthorityViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALTestAppB2CAuthorityViewController.h; sourceTree = ""; }; 1E394C432123812700CC1616 /* MSALTestAppB2CAuthorityViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALTestAppB2CAuthorityViewController.m; sourceTree = ""; }; + 1E4522AB22581B8A00D27CA7 /* MSALScopesViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALScopesViewController.h; sourceTree = ""; }; + 1E4522AC22581B8A00D27CA7 /* MSALScopesViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALScopesViewController.m; sourceTree = ""; }; + 1E614BDA22558D8300EBF62F /* MSAL Test App (Mac).app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "MSAL Test App (Mac).app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 1E614BDC22558D8300EBF62F /* MSALAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALAppDelegate.h; sourceTree = ""; }; + 1E614BDD22558D8300EBF62F /* MSALAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALAppDelegate.m; sourceTree = ""; }; + 1E614BE222558D8300EBF62F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 1E614BE522558D8300EBF62F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 1E614BE722558D8300EBF62F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1E614BE822558D8300EBF62F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 1E614BEA22558D8300EBF62F /* MSALMacTestApp.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MSALMacTestApp.entitlements; sourceTree = ""; }; 1E665DB72162A83E0049A59A /* MSALTestAppProfileViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALTestAppProfileViewController.h; sourceTree = ""; }; 1E665DB82162A83E0049A59A /* MSALTestAppProfileViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALTestAppProfileViewController.m; sourceTree = ""; }; + 1E8B002D225E81A2006BB8BD /* MSALCacheViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALCacheViewController.h; sourceTree = ""; }; + 1E8B002E225E81A2006BB8BD /* MSALCacheViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALCacheViewController.m; sourceTree = ""; }; 1E8FC6A2221F370C00B4D4C1 /* MSALResultTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALResultTests.m; sourceTree = ""; }; 1EB7ABD421262C420058C7E0 /* MSALTestAppAuthorityTypeViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALTestAppAuthorityTypeViewController.h; sourceTree = ""; }; 1EB7ABD521262C420058C7E0 /* MSALTestAppAuthorityTypeViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALTestAppAuthorityTypeViewController.m; sourceTree = ""; }; + 1EC12C0F2255DB9200339572 /* MSALAcquireTokenViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALAcquireTokenViewController.h; sourceTree = ""; }; + 1EC12C102255DB9200339572 /* MSALAcquireTokenViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALAcquireTokenViewController.m; sourceTree = ""; }; 231CE9DD1FEC684C00E95D3E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; 231CE9E01FECBD4600E95D3E /* unit-test-host.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "unit-test-host.entitlements"; sourceTree = ""; }; 232D61482248484C00260C42 /* MSALClaimsRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALClaimsRequest.h; sourceTree = ""; }; @@ -848,6 +941,9 @@ 232D68DA223DBA0700594BBD /* MSALInteractiveTokenParameters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALInteractiveTokenParameters.h; sourceTree = ""; }; 232D68DB223DBA0700594BBD /* MSALInteractiveTokenParameters.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALInteractiveTokenParameters.m; sourceTree = ""; }; 232D68FF2240A3FF00594BBD /* MSALTokenParameters+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MSALTokenParameters+Internal.h"; sourceTree = ""; }; + 233E96F922653EFC007FCE2A /* MSALTelemetryEventsObservingProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALTelemetryEventsObservingProxy.h; sourceTree = ""; }; + 233E96FA22653EFC007FCE2A /* MSALTelemetryEventsObservingProxy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALTelemetryEventsObservingProxy.m; sourceTree = ""; }; + 233E970A226571AB007FCE2A /* MSALTelemetryAggregatedTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALTelemetryAggregatedTests.m; sourceTree = ""; }; 2342584A20649A9800621AFE /* MSALAccount+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MSALAccount+Internal.h"; sourceTree = ""; }; 23576D3F2252C07700D6F7BA /* MSALClaimsRequest+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MSALClaimsRequest+Internal.h"; sourceTree = ""; }; 2364C7461FB3E52E00835428 /* XCTestCase+HelperMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "XCTestCase+HelperMethods.h"; sourceTree = ""; }; @@ -859,14 +955,15 @@ 23A68A7E20F538DE0071E435 /* MSALADFSAuthority.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALADFSAuthority.h; sourceTree = ""; }; 23A68A7F20F538DE0071E435 /* MSALADFSAuthority.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALADFSAuthority.m; sourceTree = ""; }; 23A68A8A20F5508B0071E435 /* MSALAuthority_Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALAuthority_Internal.h; sourceTree = ""; }; - 23A68A8B20F57A440071E435 /* MSALAuthorityFactory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALAuthorityFactory.h; sourceTree = ""; }; - 23A68A8C20F57A440071E435 /* MSALAuthorityFactory.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALAuthorityFactory.m; sourceTree = ""; }; 23A68A9120F59E6B0071E435 /* NSString+MSALTestUtil.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSString+MSALTestUtil.h"; sourceTree = ""; }; 23A68A9220F59E6B0071E435 /* NSString+MSALTestUtil.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSString+MSALTestUtil.m"; sourceTree = ""; }; - 23CDA9B01FA4443800FDD5C0 /* MSALTelemetryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALTelemetryTests.m; sourceTree = ""; }; 23F32F051FF4787600B2905E /* MSIDTestURLResponse+MSAL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MSIDTestURLResponse+MSAL.h"; sourceTree = ""; }; 23F32F061FF4787600B2905E /* MSIDTestURLResponse+MSAL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MSIDTestURLResponse+MSAL.m"; sourceTree = ""; }; 23FB5C1C22542B99002BF1EB /* MSALJsonDeserializable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALJsonDeserializable.h; sourceTree = ""; }; + 6077D49F22498BFF001798A2 /* MSALTenantProfile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALTenantProfile.h; sourceTree = ""; }; + 6077D4A822498D87001798A2 /* MSALTenantProfile.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALTenantProfile.m; sourceTree = ""; }; + 609AF9322256BD0C00E2978D /* MSALAccountsProviderTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALAccountsProviderTests.m; sourceTree = ""; }; + 609AF958225B348900E2978D /* MSALTenantProfile+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MSALTenantProfile+Internal.h"; sourceTree = ""; }; 60DEF15A1E67756800966664 /* MSAL Test App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = "MSAL Test App.entitlements"; path = "../../../../MSAL Test App.entitlements"; sourceTree = ""; }; 94E876B01E4556B400FB96ED /* MSAL.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSAL.pch; sourceTree = ""; }; 94E876CA1E492D6000FB96ED /* MSALAuthority.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSALAuthority.h; sourceTree = ""; }; @@ -938,6 +1035,14 @@ B221CED920C0AC60002F5E94 /* MSALAccountId.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALAccountId.h; sourceTree = ""; }; B221CEDA20C0AC60002F5E94 /* MSALAccountId.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALAccountId.m; sourceTree = ""; }; B221CEEA20C0AF0B002F5E94 /* MSALAccountId+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MSALAccountId+Internal.h"; sourceTree = ""; }; + B223B0B122ADF8C500FB8713 /* MSALLegacySharedADALAccount.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALLegacySharedADALAccount.h; sourceTree = ""; }; + B223B0B222ADF8C500FB8713 /* MSALLegacySharedADALAccount.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALLegacySharedADALAccount.m; sourceTree = ""; }; + B223B0B722ADF8E600FB8713 /* MSALLegacySharedMSAAccount.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALLegacySharedMSAAccount.h; sourceTree = ""; }; + B223B0B822ADF8E600FB8713 /* MSALLegacySharedMSAAccount.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALLegacySharedMSAAccount.m; sourceTree = ""; }; + B223B0BD22ADFACB00FB8713 /* MSALLegacySharedAccount.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALLegacySharedAccount.h; sourceTree = ""; }; + B223B0BE22ADFACB00FB8713 /* MSALLegacySharedAccount.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALLegacySharedAccount.m; sourceTree = ""; }; + B223B0C322AE215D00FB8713 /* MSALLegacySharedAccountFactory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALLegacySharedAccountFactory.h; sourceTree = ""; }; + B223B0C422AE215D00FB8713 /* MSALLegacySharedAccountFactory.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALLegacySharedAccountFactory.m; sourceTree = ""; }; B2472CA2226FDC46008F22AB /* MSALB2CAuthority_Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALB2CAuthority_Internal.h; sourceTree = ""; }; B256121A217EA44900999876 /* MSALOauth2FactoryProducerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALOauth2FactoryProducerTests.m; sourceTree = ""; }; B25A39D721C4C49D00213A62 /* MSALAutomationExpireATAction.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALAutomationExpireATAction.h; sourceTree = ""; }; @@ -961,17 +1066,61 @@ B25F1BC01EC3DD3200474D1B /* MSALUser+Automation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MSALUser+Automation.m"; sourceTree = ""; }; B25F1BC21EC3E44500474D1B /* MSALResult+Automation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MSALResult+Automation.h"; sourceTree = ""; }; B25F1BC31EC3E44500474D1B /* MSALResult+Automation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MSALResult+Automation.m"; sourceTree = ""; }; + B2659C862287D13B00F5A0C3 /* MSALSerializedADALCacheProvider+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MSALSerializedADALCacheProvider+Internal.h"; sourceTree = ""; }; + B266391922B4B84600FEB673 /* NSString+MSALAccountIdenfiers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSString+MSALAccountIdenfiers.h"; sourceTree = ""; }; + B266391A22B4B84600FEB673 /* NSString+MSALAccountIdenfiers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSString+MSALAccountIdenfiers.m"; sourceTree = ""; }; + B267569B228F335E000F01D7 /* MSALExternalAccountHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALExternalAccountHandler.h; sourceTree = ""; }; + B267569C228F335E000F01D7 /* MSALExternalAccountHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALExternalAccountHandler.m; sourceTree = ""; }; + B26756BC22921A71000F01D7 /* MSALOauth2Provider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALOauth2Provider.h; sourceTree = ""; }; + B26756BD22921A71000F01D7 /* MSALOauth2Provider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALOauth2Provider.m; sourceTree = ""; }; + B26756C222921C42000F01D7 /* MSALAADOauth2Provider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALAADOauth2Provider.h; sourceTree = ""; }; + B26756C322921C42000F01D7 /* MSALAADOauth2Provider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALAADOauth2Provider.m; sourceTree = ""; }; + B26756C822921C5B000F01D7 /* MSALB2COauth2Provider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALB2COauth2Provider.h; sourceTree = ""; }; + B26756C922921C5B000F01D7 /* MSALB2COauth2Provider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALB2COauth2Provider.m; sourceTree = ""; }; + B26756CE22921C6D000F01D7 /* MSALADFSOauth2Provider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALADFSOauth2Provider.h; sourceTree = ""; }; + B26756CF22921C6D000F01D7 /* MSALADFSOauth2Provider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALADFSOauth2Provider.m; sourceTree = ""; }; + B26756D422921CC4000F01D7 /* MSALOauth2Provider+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MSALOauth2Provider+Internal.h"; sourceTree = ""; }; + B26756D722922375000F01D7 /* MSALOauth2Authority.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALOauth2Authority.h; sourceTree = ""; }; + B26756D822922375000F01D7 /* MSALOauth2Authority.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALOauth2Authority.m; sourceTree = ""; }; B26D3107211680B2002B493F /* MSALMSABasicInteractiveTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALMSABasicInteractiveTests.m; sourceTree = ""; }; + B2725E7E22BD88BE009B454A /* NSStringAccountIdentifiersTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NSStringAccountIdentifiersTest.m; sourceTree = ""; }; + B2725EAB22BF2759009B454A /* MSALExternalAccountHandlerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALExternalAccountHandlerTests.m; sourceTree = ""; }; + B2725EB422BF2774009B454A /* MSALPublicClientApplicationAccountUpdateTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALPublicClientApplicationAccountUpdateTests.m; sourceTree = ""; }; + B2725EB722BF27FF009B454A /* MSALMockExternalAccountHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALMockExternalAccountHandler.h; sourceTree = ""; }; + B2725EB822BF27FF009B454A /* MSALMockExternalAccountHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALMockExternalAccountHandler.m; sourceTree = ""; }; + B2725EC922C04661009B454A /* MSALLegacySharedAccountTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALLegacySharedAccountTests.m; sourceTree = ""; }; + B2725ECB22C0466E009B454A /* MSALLegacySharedADALAccountTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALLegacySharedADALAccountTests.m; sourceTree = ""; }; + B2725ECD22C04679009B454A /* MSALLegacySharedMSAAccountTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALLegacySharedMSAAccountTests.m; sourceTree = ""; }; + B2725ECF22C04689009B454A /* MSALLegacySharedAccountFactoryTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALLegacySharedAccountFactoryTests.m; sourceTree = ""; }; + B2725ED122C0469A009B454A /* MSALLegacySharedAccountsProviderTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALLegacySharedAccountsProviderTests.m; sourceTree = ""; }; B2734C1921253ABB00DAB1CD /* MSALUnifiedADALCacheCoexistenceTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALUnifiedADALCacheCoexistenceTests.m; sourceTree = ""; }; B2734C1B21253AD300DAB1CD /* MSALMultiAppCacheCoexistenceTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALMultiAppCacheCoexistenceTests.m; sourceTree = ""; }; B2734C1D21253B1B00DAB1CD /* MSALDotNetCacheCoexistenceTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALDotNetCacheCoexistenceTests.m; sourceTree = ""; }; B277241C1EAE97D700375C53 /* MSALStressTestHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSALStressTestHelper.h; sourceTree = ""; }; B277241D1EAE97D700375C53 /* MSALStressTestHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALStressTestHelper.m; sourceTree = ""; }; + B27CCDDE229F65D700CAD565 /* MSALAccount+MultiTenantAccount.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MSALAccount+MultiTenantAccount.h"; sourceTree = ""; }; + B27CCDF0229F9F4700CAD565 /* MSALAccountEnumerationParameters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALAccountEnumerationParameters.h; sourceTree = ""; }; + B27CCDF1229F9F4700CAD565 /* MSALAccountEnumerationParameters.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALAccountEnumerationParameters.m; sourceTree = ""; }; B281B33A226BC225009619AB /* MSALPublicClientApplicationConfigTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALPublicClientApplicationConfigTests.m; sourceTree = ""; }; B28BBD312211DC7D00F51723 /* MSALPublicClientStatusNotifications.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALPublicClientStatusNotifications.h; sourceTree = ""; }; B28BBD322211DC7D00F51723 /* MSALPublicClientStatusNotifications.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALPublicClientStatusNotifications.m; sourceTree = ""; }; - B28BDA8C217E9EAB003E5670 /* MSALOauth2FactoryProducer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALOauth2FactoryProducer.h; sourceTree = ""; }; - B28BDA8D217E9EAB003E5670 /* MSALOauth2FactoryProducer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALOauth2FactoryProducer.m; sourceTree = ""; }; + B28BDA8C217E9EAB003E5670 /* MSALOauth2ProviderFactory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALOauth2ProviderFactory.h; sourceTree = ""; }; + B28BDA8D217E9EAB003E5670 /* MSALOauth2ProviderFactory.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALOauth2ProviderFactory.m; sourceTree = ""; }; + B295A16422D0348400FFB313 /* unit-test-host-mac.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "unit-test-host-mac.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + B295A16622D0348400FFB313 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + B295A16722D0348400FFB313 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + B295A16922D0348400FFB313 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; + B295A16A22D0348400FFB313 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; + B295A16C22D0348600FFB313 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + B295A16F22D0348600FFB313 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + B295A17122D0348600FFB313 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B295A17222D0348600FFB313 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + B29A56A4228262770023F5E6 /* MSALExternalAccountProviding.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALExternalAccountProviding.h; sourceTree = ""; }; + B29A56B8228266B40023F5E6 /* MSALSerializedADALCacheProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALSerializedADALCacheProvider.h; sourceTree = ""; }; + B29A56B9228266B40023F5E6 /* MSALSerializedADALCacheProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALSerializedADALCacheProvider.m; sourceTree = ""; }; + B29A56BD228266E20023F5E6 /* MSALLegacySharedAccountsProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALLegacySharedAccountsProvider.h; sourceTree = ""; }; + B29A56BE228266E20023F5E6 /* MSALLegacySharedAccountsProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALLegacySharedAccountsProvider.m; sourceTree = ""; }; + B29A56CE2283D7430023F5E6 /* MSALAADAuthorityTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALAADAuthorityTests.m; sourceTree = ""; }; B29E2AC421238E0000B170ED /* SafariServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SafariServices.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.4.sdk/System/Library/Frameworks/SafariServices.framework; sourceTree = DEVELOPER_DIR; }; B29E2AC821238F2200B170ED /* MSALNonUnifiedADALCoexistenceCacheTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALNonUnifiedADALCoexistenceCacheTests.m; sourceTree = ""; }; B29E2ACE21238F5200B170ED /* MultiAppiOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MultiAppiOSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -979,10 +1128,8 @@ B2A3C2882145FD0F0082525C /* MSALAccountsProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALAccountsProvider.m; sourceTree = ""; }; B2AD63481EA5663800EFEEF1 /* MSALTestAppTelemetryViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSALTestAppTelemetryViewController.h; sourceTree = ""; }; B2AD63491EA5663800EFEEF1 /* MSALTestAppTelemetryViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALTestAppTelemetryViewController.m; sourceTree = ""; }; - B2AD634B1EA5665F00EFEEF1 /* MSALTestAppTelemetryDispatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSALTestAppTelemetryDispatcher.h; sourceTree = ""; }; - B2AD634C1EA5665F00EFEEF1 /* MSALTestAppTelemetryDispatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALTestAppTelemetryDispatcher.m; sourceTree = ""; }; - B2B5F0891FCA61EB00F6AFAD /* MSALTelemetryDefaultEvent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALTelemetryDefaultEvent.h; sourceTree = ""; }; - B2B5F08A1FCA61EB00F6AFAD /* MSALTelemetryDefaultEvent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALTelemetryDefaultEvent.m; sourceTree = ""; }; + B2ADD76C22C08B6A0093FD43 /* MSALLegacySharedAccountTestUtil.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALLegacySharedAccountTestUtil.h; sourceTree = ""; }; + B2ADD76D22C08B6A0093FD43 /* MSALLegacySharedAccountTestUtil.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALLegacySharedAccountTestUtil.m; sourceTree = ""; }; B2BB73702112C32C000EA4C5 /* InteractiveiOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteractiveiOSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; B2BB73722112C32C000EA4C5 /* MSALAADBasicInteractiveTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALAADBasicInteractiveTests.m; sourceTree = ""; }; B2BB73742112C32C000EA4C5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -1012,17 +1159,10 @@ D61A64331E5A29580086D120 /* MSAL Test App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "MSAL Test App.app"; sourceTree = BUILT_PRODUCTS_DIR; }; D61A64661E5AA6B40086D120 /* msal__test_app__ios.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = msal__test_app__ios.xcconfig; sourceTree = ""; }; D61A64671E5AA6BE0086D120 /* msal__test_app__mac.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = msal__test_app__mac.xcconfig; sourceTree = ""; }; - D61A646C1E5AA7120086D120 /* MSAL Test App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "MSAL Test App.app"; sourceTree = BUILT_PRODUCTS_DIR; }; D61A647F1E5AA7C60086D120 /* MSALTestAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALTestAppDelegate.h; sourceTree = ""; }; D61A64801E5AA7C60086D120 /* MSALTestAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALTestAppDelegate.m; sourceTree = ""; }; D61A64811E5AA7C60086D120 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; D61A64881E5AA7C60086D120 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - D61A648C1E5AA7C60086D120 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - D61A648D1E5AA7C60086D120 /* MSALTestAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALTestAppDelegate.h; sourceTree = ""; }; - D61A648E1E5AA7C60086D120 /* MSALTestAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSALTestAppDelegate.m; sourceTree = ""; }; - D61A64901E5AA7C60086D120 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - D61A64921E5AA7C60086D120 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - D61A64931E5AA7C60086D120 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; D61A649D1E5AABC50086D120 /* MSALTestAppAcquireTokenViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALTestAppAcquireTokenViewController.m; sourceTree = ""; }; D61A649E1E5AABC50086D120 /* MSALTestAppAcquireLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSALTestAppAcquireLayoutBuilder.h; sourceTree = ""; }; D61A649F1E5AABC50086D120 /* MSALTestAppAcquireLayoutBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALTestAppAcquireLayoutBuilder.m; sourceTree = ""; }; @@ -1042,7 +1182,7 @@ D61F5BC21E59193500912CB8 /* MSALFakeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALFakeViewController.m; sourceTree = ""; }; D61F5BC91E59359900912CB8 /* MSALFramework.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALFramework.m; sourceTree = ""; }; D62746D11E9B38AF00EFCE99 /* MSALPublicClientApplication+Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MSALPublicClientApplication+Internal.h"; sourceTree = ""; }; - D62746D81E9B5F1E00EFCE99 /* MSALUserTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALUserTests.m; sourceTree = ""; }; + D62746D81E9B5F1E00EFCE99 /* MSALAccountTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALAccountTests.m; sourceTree = ""; }; D659D4E21E5EBB49007FBCF7 /* MSALTestAppUserViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSALTestAppUserViewController.h; sourceTree = ""; }; D659D4E31E5EBB49007FBCF7 /* MSALTestAppUserViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALTestAppUserViewController.m; sourceTree = ""; }; D659D4ED1E64BEA3007FBCF7 /* MSALTestAppSettingViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSALTestAppSettingViewController.h; sourceTree = ""; }; @@ -1110,12 +1250,7 @@ D6A206371FC510B500755A51 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; D6A2063B1FC510FB00755A51 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; D6B58A531EB2C4A8000B3A5F /* MSALAcquireTokenTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALAcquireTokenTests.m; sourceTree = ""; }; - E02396D11E776F10004D6278 /* MSALDefaultDispatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSALDefaultDispatcher.h; sourceTree = ""; }; - E02396D21E776F10004D6278 /* MSALDefaultDispatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALDefaultDispatcher.m; sourceTree = ""; }; E02396F31E79E2F4004D6278 /* MSALTelemetryApiId.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSALTelemetryApiId.h; sourceTree = ""; }; - E02396F81E7B005C004D6278 /* MSALTelemetryTestDispatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSALTelemetryTestDispatcher.h; sourceTree = ""; }; - E02396F91E7B005C004D6278 /* MSALTelemetryTestDispatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSALTelemetryTestDispatcher.m; sourceTree = ""; }; - E02396FC1E7B0E20004D6278 /* MSALTelemetryDispatcherTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MSALTelemetryDispatcherTests.m; path = telemetry/MSALTelemetryDispatcherTests.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1135,6 +1270,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 1E614BD722558D8300EBF62F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1E8B0026225E8019006BB8BD /* WebKit.framework in Frameworks */, + 1E1A2E062256D194001009ED /* AppKit.framework in Frameworks */, + 1EC12C3A2256BC6800339572 /* MSAL.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 962E37B51E720C5D00DE71FE /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1148,6 +1293,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + B295A16122D0348400FFB313 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B295A17A22D0352600FFB313 /* AppKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; B29E2ACB21238F5200B170ED /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1182,15 +1335,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - D61A64691E5AA7120086D120 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - D6A206411FC514CE00755A51 /* Cocoa.framework in Frameworks */, - D62B8FD41E6789DD009D6E7E /* MSAL.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; D65A6F3F1E3FD30A00C69FBA /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1255,18 +1399,19 @@ 94E876C91E492D2800FB96ED /* instance */ = { isa = PBXGroup; children = ( + B26756B822921A30000F01D7 /* oauth2 */, 23A68A8A20F5508B0071E435 /* MSALAuthority_Internal.h */, 94E876CB1E492D6000FB96ED /* MSALAuthority.m */, 23A68A7320F5386A0071E435 /* MSALAADAuthority.m */, B2472CA2226FDC46008F22AB /* MSALB2CAuthority_Internal.h */, 23A68A7920F538B90071E435 /* MSALB2CAuthority.m */, 23A68A7F20F538DE0071E435 /* MSALADFSAuthority.m */, - 23A68A8B20F57A440071E435 /* MSALAuthorityFactory.h */, - 23A68A8C20F57A440071E435 /* MSALAuthorityFactory.m */, - B28BDA8C217E9EAB003E5670 /* MSALOauth2FactoryProducer.h */, - B28BDA8D217E9EAB003E5670 /* MSALOauth2FactoryProducer.m */, + B28BDA8C217E9EAB003E5670 /* MSALOauth2ProviderFactory.h */, + B28BDA8D217E9EAB003E5670 /* MSALOauth2ProviderFactory.m */, B2A3C2872145FD0F0082525C /* MSALAccountsProvider.h */, B2A3C2882145FD0F0082525C /* MSALAccountsProvider.m */, + B26756D722922375000F01D7 /* MSALOauth2Authority.h */, + B26756D822922375000F01D7 /* MSALOauth2Authority.m */, ); path = instance; sourceTree = ""; @@ -1284,8 +1429,8 @@ 9626D151225828A00019417B /* publicClientApplication */ = { isa = PBXGroup; children = ( + B29A56A32282622F0023F5E6 /* cache */, 96B5E6EA2256D180002232F9 /* MSALSliceConfig.h */, - 96B5E6CC2256D152002232F9 /* MSALCacheConfig.h */, ); path = publicClientApplication; sourceTree = ""; @@ -1293,6 +1438,7 @@ 9626D153225835D50019417B /* configuration */ = { isa = PBXGroup; children = ( + B2659C792287BBB000F5A0C3 /* external */, 9627C7B7225431FA0028A859 /* MSALPublicClientApplicationConfig+Internal.h */, 9627C7AC22542EDC0028A859 /* MSALPublicClientApplicationConfig.m */, 9648AF5B225DD6A900F66801 /* MSALGlobalConfig+Internal.h */, @@ -1360,10 +1506,9 @@ 96D9A5461E4AB21400674A85 /* telemetry */ = { isa = PBXGroup; children = ( - E02396D41E787D60004D6278 /* events */, 96D9A5471E4AB22900674A85 /* MSALTelemetry.m */, - E02396D11E776F10004D6278 /* MSALDefaultDispatcher.h */, - E02396D21E776F10004D6278 /* MSALDefaultDispatcher.m */, + 233E96F922653EFC007FCE2A /* MSALTelemetryEventsObservingProxy.h */, + 233E96FA22653EFC007FCE2A /* MSALTelemetryEventsObservingProxy.m */, ); path = telemetry; sourceTree = ""; @@ -1410,6 +1555,149 @@ path = util; sourceTree = ""; }; + B2659C792287BBB000F5A0C3 /* external */ = { + isa = PBXGroup; + children = ( + B2725EC722C04562009B454A /* ios */, + B29A56B9228266B40023F5E6 /* MSALSerializedADALCacheProvider.m */, + B2659C862287D13B00F5A0C3 /* MSALSerializedADALCacheProvider+Internal.h */, + B267569B228F335E000F01D7 /* MSALExternalAccountHandler.h */, + B267569C228F335E000F01D7 /* MSALExternalAccountHandler.m */, + ); + path = external; + sourceTree = ""; + }; + B26756B822921A30000F01D7 /* oauth2 */ = { + isa = PBXGroup; + children = ( + B26756BB22921A60000F01D7 /* adfs */, + B26756BA22921A5B000F01D7 /* b2c */, + B26756B922921A51000F01D7 /* aad */, + B26756BC22921A71000F01D7 /* MSALOauth2Provider.h */, + B26756BD22921A71000F01D7 /* MSALOauth2Provider.m */, + B26756D422921CC4000F01D7 /* MSALOauth2Provider+Internal.h */, + ); + path = oauth2; + sourceTree = ""; + }; + B26756B922921A51000F01D7 /* aad */ = { + isa = PBXGroup; + children = ( + B26756C222921C42000F01D7 /* MSALAADOauth2Provider.h */, + B26756C322921C42000F01D7 /* MSALAADOauth2Provider.m */, + ); + path = aad; + sourceTree = ""; + }; + B26756BA22921A5B000F01D7 /* b2c */ = { + isa = PBXGroup; + children = ( + B26756C822921C5B000F01D7 /* MSALB2COauth2Provider.h */, + B26756C922921C5B000F01D7 /* MSALB2COauth2Provider.m */, + ); + path = b2c; + sourceTree = ""; + }; + B26756BB22921A60000F01D7 /* adfs */ = { + isa = PBXGroup; + children = ( + B26756CE22921C6D000F01D7 /* MSALADFSOauth2Provider.h */, + B26756CF22921C6D000F01D7 /* MSALADFSOauth2Provider.m */, + ); + path = adfs; + sourceTree = ""; + }; + B2725EBD22BF2805009B454A /* mocks */ = { + isa = PBXGroup; + children = ( + B2725EB722BF27FF009B454A /* MSALMockExternalAccountHandler.h */, + B2725EB822BF27FF009B454A /* MSALMockExternalAccountHandler.m */, + ); + path = mocks; + sourceTree = ""; + }; + B2725EC722C04562009B454A /* ios */ = { + isa = PBXGroup; + children = ( + B29A56BE228266E20023F5E6 /* MSALLegacySharedAccountsProvider.m */, + B223B0B122ADF8C500FB8713 /* MSALLegacySharedADALAccount.h */, + B223B0B222ADF8C500FB8713 /* MSALLegacySharedADALAccount.m */, + B223B0B722ADF8E600FB8713 /* MSALLegacySharedMSAAccount.h */, + B223B0B822ADF8E600FB8713 /* MSALLegacySharedMSAAccount.m */, + B223B0BD22ADFACB00FB8713 /* MSALLegacySharedAccount.h */, + B223B0BE22ADFACB00FB8713 /* MSALLegacySharedAccount.m */, + B223B0C322AE215D00FB8713 /* MSALLegacySharedAccountFactory.h */, + B223B0C422AE215D00FB8713 /* MSALLegacySharedAccountFactory.m */, + B266391922B4B84600FEB673 /* NSString+MSALAccountIdenfiers.h */, + B266391A22B4B84600FEB673 /* NSString+MSALAccountIdenfiers.m */, + ); + path = ios; + sourceTree = ""; + }; + B2725EC822C04638009B454A /* external-cache */ = { + isa = PBXGroup; + children = ( + B2725E7E22BD88BE009B454A /* NSStringAccountIdentifiersTest.m */, + B2725EC922C04661009B454A /* MSALLegacySharedAccountTests.m */, + B2725ECB22C0466E009B454A /* MSALLegacySharedADALAccountTests.m */, + B2725ECD22C04679009B454A /* MSALLegacySharedMSAAccountTests.m */, + B2725ECF22C04689009B454A /* MSALLegacySharedAccountFactoryTests.m */, + B2725ED122C0469A009B454A /* MSALLegacySharedAccountsProviderTests.m */, + B2ADD76C22C08B6A0093FD43 /* MSALLegacySharedAccountTestUtil.h */, + B2ADD76D22C08B6A0093FD43 /* MSALLegacySharedAccountTestUtil.m */, + ); + path = "external-cache"; + sourceTree = ""; + }; + B295A15E22D0344B00FFB313 /* mac */ = { + isa = PBXGroup; + children = ( + B295A15F22D0345100FFB313 /* unit-test-host */, + ); + path = mac; + sourceTree = ""; + }; + B295A15F22D0345100FFB313 /* unit-test-host */ = { + isa = PBXGroup; + children = ( + B295A16622D0348400FFB313 /* AppDelegate.h */, + B295A16722D0348400FFB313 /* AppDelegate.m */, + B295A16922D0348400FFB313 /* ViewController.h */, + B295A16A22D0348400FFB313 /* ViewController.m */, + B295A16C22D0348600FFB313 /* Assets.xcassets */, + B295A16E22D0348600FFB313 /* Main.storyboard */, + B295A17122D0348600FFB313 /* Info.plist */, + B295A17222D0348600FFB313 /* main.m */, + ); + path = "unit-test-host"; + sourceTree = ""; + }; + B2968C4122F24259005AFC33 /* ios */ = { + isa = PBXGroup; + children = ( + B2968C4222F24265005AFC33 /* cache */, + ); + path = ios; + sourceTree = ""; + }; + B2968C4222F24265005AFC33 /* cache */ = { + isa = PBXGroup; + children = ( + B29A56BD228266E20023F5E6 /* MSALLegacySharedAccountsProvider.h */, + ); + path = cache; + sourceTree = ""; + }; + B29A56A32282622F0023F5E6 /* cache */ = { + isa = PBXGroup; + children = ( + 96B5E6CC2256D152002232F9 /* MSALCacheConfig.h */, + B29A56A4228262770023F5E6 /* MSALExternalAccountProviding.h */, + B29A56B8228266B40023F5E6 /* MSALSerializedADALCacheProvider.h */, + ); + path = cache; + sourceTree = ""; + }; B2BB737F2112C351000EA4C5 /* tests */ = { isa = PBXGroup; children = ( @@ -1504,8 +1792,6 @@ D67C8A171E65104200857D40 /* MSALTestAppAuthorityViewController.m */, 96CFA0081E6E3454003BFCDC /* MSALTestAppScopesViewController.h */, 96CFA0091E6E3454003BFCDC /* MSALTestAppScopesViewController.m */, - B2AD634B1EA5665F00EFEEF1 /* MSALTestAppTelemetryDispatcher.h */, - B2AD634C1EA5665F00EFEEF1 /* MSALTestAppTelemetryDispatcher.m */, B2AD63481EA5663800EFEEF1 /* MSALTestAppTelemetryViewController.h */, B2AD63491EA5663800EFEEF1 /* MSALTestAppTelemetryViewController.m */, 1E394C422123812700CC1616 /* MSALTestAppB2CAuthorityViewController.h */, @@ -1531,24 +1817,23 @@ D61A648B1E5AA7C60086D120 /* mac */ = { isa = PBXGroup; children = ( - D61A648C1E5AA7C60086D120 /* main.m */, - D61A648D1E5AA7C60086D120 /* MSALTestAppDelegate.h */, - D61A648E1E5AA7C60086D120 /* MSALTestAppDelegate.m */, - D61A648F1E5AA7C60086D120 /* resources */, + 1E614BDC22558D8300EBF62F /* MSALAppDelegate.h */, + 1E614BDD22558D8300EBF62F /* MSALAppDelegate.m */, + 1E614BE222558D8300EBF62F /* Assets.xcassets */, + 1E614BE422558D8300EBF62F /* Main.storyboard */, + 1E614BE722558D8300EBF62F /* Info.plist */, + 1E614BE822558D8300EBF62F /* main.m */, + 1E614BEA22558D8300EBF62F /* MSALMacTestApp.entitlements */, + 1EC12C0F2255DB9200339572 /* MSALAcquireTokenViewController.h */, + 1EC12C102255DB9200339572 /* MSALAcquireTokenViewController.m */, + 1E4522AB22581B8A00D27CA7 /* MSALScopesViewController.h */, + 1E4522AC22581B8A00D27CA7 /* MSALScopesViewController.m */, + 1E8B002D225E81A2006BB8BD /* MSALCacheViewController.h */, + 1E8B002E225E81A2006BB8BD /* MSALCacheViewController.m */, ); path = mac; sourceTree = ""; }; - D61A648F1E5AA7C60086D120 /* resources */ = { - isa = PBXGroup; - children = ( - D61A64901E5AA7C60086D120 /* Assets.xcassets */, - D61A64911E5AA7C60086D120 /* MainMenu.xib */, - D61A64931E5AA7C60086D120 /* Info.plist */, - ); - path = resources; - sourceTree = ""; - }; D61F5B691E53FCA100912CB8 /* test */ = { isa = PBXGroup; children = ( @@ -1610,6 +1895,7 @@ D65A6F7A1E3FF3D900C69FBA /* MSALAccount.m */, B221CEEA20C0AF0B002F5E94 /* MSALAccountId+Internal.h */, B221CEDA20C0AC60002F5E94 /* MSALAccountId.m */, + 6077D4A822498D87001798A2 /* MSALTenantProfile.m */, 94E876B01E4556B400FB96ED /* MSAL.pch */, D69ADB191E50525F00952049 /* MSALPromptType_Internal.h */, D69ADB1A1E50531300952049 /* MSALPromptType.m */, @@ -1619,10 +1905,12 @@ D61A63F11E5979200086D120 /* MSALResult+Internal.h */, B2C17B091FC8DB2E0070A514 /* MSIDVersion.m */, B28BBD322211DC7D00F51723 /* MSALPublicClientStatusNotifications.m */, + 609AF958225B348900E2978D /* MSALTenantProfile+Internal.h */, 232D68FF2240A3FF00594BBD /* MSALTokenParameters+Internal.h */, 232D68C9223DB00500594BBD /* MSALTokenParameters.m */, 232D68DB223DBA0700594BBD /* MSALInteractiveTokenParameters.m */, 232D68D5223DB8C200594BBD /* MSALSilentTokenParameters.m */, + B27CCDF1229F9F4700CAD565 /* MSALAccountEnumerationParameters.m */, ); path = src; sourceTree = ""; @@ -1637,6 +1925,8 @@ D65A6F841E3FF3D900C69FBA /* MSALPublicClientApplication.h */, D65A6F851E3FF3D900C69FBA /* MSALResult.h */, D65A6F861E3FF3D900C69FBA /* MSALAccount.h */, + B27CCDDE229F65D700CAD565 /* MSALAccount+MultiTenantAccount.h */, + 6077D49F22498BFF001798A2 /* MSALTenantProfile.h */, B221CED920C0AC60002F5E94 /* MSALAccountId.h */, 94E876CA1E492D6000FB96ED /* MSALAuthority.h */, 23A68A7220F5386A0071E435 /* MSALAADAuthority.h */, @@ -1654,6 +1944,8 @@ 232D616022485BA700260C42 /* MSALIndividualClaimRequestAdditionalInfo.h */, 232D616922498EDF00260C42 /* MSALJsonSerializable.h */, 23FB5C1C22542B99002BF1EB /* MSALJsonDeserializable.h */, + B27CCDF0229F9F4700CAD565 /* MSALAccountEnumerationParameters.h */, + B2968C4122F24259005AFC33 /* ios */, ); path = public; sourceTree = ""; @@ -1711,20 +2003,26 @@ D65A6FDB1E3FF71000C69FBA /* unit */ = { isa = PBXGroup; children = ( - E02396F51E7AFFF7004D6278 /* telemetry */, + B295A15E22D0344B00FFB313 /* mac */, + B2725EBD22BF2805009B454A /* mocks */, D65A6FDC1E3FF71000C69FBA /* ios */, D65A6FDE1E3FF71000C69FBA /* resources */, D69ADB281E516F9B00952049 /* utils */, + E02396F51E7AFFF7004D6278 /* telemetry */, D673F07C1E4AAB0D0018BA91 /* MSALPublicClientApplicationTests.m */, - D62746D81E9B5F1E00EFCE99 /* MSALUserTests.m */, + D62746D81E9B5F1E00EFCE99 /* MSALAccountTests.m */, D6B58A531EB2C4A8000B3A5F /* MSALAcquireTokenTests.m */, B25F1BB21EC257F900474D1B /* MSALB2CPolicyTests.m */, 04D32CCF1FD8AFF3000B123E /* MSALErrorConverterTests.m */, 960751BA2183E82C00F2BF2F /* MSALAccountIdTests.m */, B256121A217EA44900999876 /* MSALOauth2FactoryProducerTests.m */, 1E8FC6A2221F370C00B4D4C1 /* MSALResultTests.m */, + 609AF9322256BD0C00E2978D /* MSALAccountsProviderTests.m */, 232D6191224C53E500260C42 /* MSALClaimsRequestTests.m */, B281B33A226BC225009619AB /* MSALPublicClientApplicationConfigTests.m */, + B29A56CE2283D7430023F5E6 /* MSALAADAuthorityTests.m */, + B2725EAB22BF2759009B454A /* MSALExternalAccountHandlerTests.m */, + B2725EB422BF2774009B454A /* MSALPublicClientApplicationAccountUpdateTests.m */, ); path = unit; sourceTree = ""; @@ -1732,6 +2030,7 @@ D65A6FDC1E3FF71000C69FBA /* ios */ = { isa = PBXGroup; children = ( + B2725EC822C04638009B454A /* external-cache */, D67227A01EBD111900F3422A /* unit-test-host */, B21E07BF210E56DD007E3A3C /* MSALRedirectUriVerifierTests.m */, ); @@ -1841,6 +2140,7 @@ D6A2062E1FC5106F00755A51 /* Frameworks */ = { isa = PBXGroup; children = ( + 1E1A2E052256D194001009ED /* AppKit.framework */, 963C89A6214BA1760051AFEE /* AuthenticationServices.framework */, B20E245C21FEB3650037CA5E /* AuthenticationServices.framework */, B29E2AC421238E0000B170ED /* SafariServices.framework */, @@ -1882,33 +2182,22 @@ D65A6FC11E3FF47D00C69FBA /* "MSAL-iOS-UI-Tests".xctest */, D65A6FD01E3FF49C00C69FBA /* "MSAL-Mac-Unit-Tests".xctest */, D61A64331E5A29580086D120 /* MSAL Test App.app */, - D61A646C1E5AA7120086D120 /* MSAL Test App.app */, 962E37BC1E720C5D00DE71FE /* MSAL Test Automation (iOS).app */, D672279F1EBD111900F3422A /* unit-test-host.app */, B2BB73702112C32C000EA4C5 /* InteractiveiOSTests.xctest */, B29E2ACE21238F5200B170ED /* MultiAppiOSTests.xctest */, + 1E614BDA22558D8300EBF62F /* MSAL Test App (Mac).app */, 04A6B57B226921890035C7C2 /* libMSAL.a */, 04A6B59C2269286F0035C7C2 /* libMSAL.a */, + B295A16422D0348400FFB313 /* unit-test-host-mac.app */, ); name = Products; sourceTree = ""; }; - E02396D41E787D60004D6278 /* events */ = { - isa = PBXGroup; - children = ( - B2B5F0891FCA61EB00F6AFAD /* MSALTelemetryDefaultEvent.h */, - B2B5F08A1FCA61EB00F6AFAD /* MSALTelemetryDefaultEvent.m */, - ); - name = events; - sourceTree = ""; - }; E02396F51E7AFFF7004D6278 /* telemetry */ = { isa = PBXGroup; children = ( - E02396F81E7B005C004D6278 /* MSALTelemetryTestDispatcher.h */, - E02396F91E7B005C004D6278 /* MSALTelemetryTestDispatcher.m */, - E02396FC1E7B0E20004D6278 /* MSALTelemetryDispatcherTests.m */, - 23CDA9B01FA4443800FDD5C0 /* MSALTelemetryTests.m */, + 233E970A226571AB007FCE2A /* MSALTelemetryAggregatedTests.m */, ); name = telemetry; sourceTree = ""; @@ -1921,6 +2210,7 @@ buildActionMask = 2147483647; files = ( B273D0CA226E85C7005A7BB4 /* MSALHTTPConfig+Internal.h in Headers */, + 238BA01B227BCAEE00A5BACD /* MSALTenantProfile.h in Headers */, 04A6B603226938120035C7C2 /* MSALLogger.h in Headers */, B273D0E9226E85FB005A7BB4 /* MSALResult+Internal.h in Headers */, B273D084226E8515005A7BB4 /* MSALSilentTokenParameters.h in Headers */, @@ -1930,13 +2220,12 @@ B273D07A226E84E2005A7BB4 /* MSALLoggerConfig.h in Headers */, B273D07E226E8500005A7BB4 /* MSALRedirectUri.h in Headers */, B273D080226E8508005A7BB4 /* MSALPublicClientStatusNotifications.h in Headers */, - B273D074226E84CF005A7BB4 /* MSALCacheConfig.h in Headers */, B273D0DF226E85E0005A7BB4 /* MSALExtraQueryParameters.h in Headers */, B273D0E5226E85F3005A7BB4 /* MSALPromptType_Internal.h in Headers */, 04A6B6072269381F0035C7C2 /* MSAL.h in Headers */, B273D076226E84D6005A7BB4 /* MSALTelemetryConfig.h in Headers */, B273D0AD226E8585005A7BB4 /* MSALErrorConverter+Internal.h in Headers */, - 04A6B5D92269379B0035C7C2 /* MSALTelemetryDefaultEvent.h in Headers */, + 04A6B5D92269379B0035C7C2 /* (null) in Headers */, 04A6B5C0226937530035C7C2 /* MSALAccount+Internal.h in Headers */, 04A6B6002269380A0035C7C2 /* MSALPublicClientApplication.h in Headers */, B273D0AC226E8581005A7BB4 /* MSALTelemetryApiId.h in Headers */, @@ -1944,7 +2233,7 @@ B273D08C226E852A005A7BB4 /* MSALIndividualClaimRequestAdditionalInfo.h in Headers */, 04A6B5F9226937F20035C7C2 /* MSALTelemetry.h in Headers */, 04A6B5CF226937800035C7C2 /* MSALRedirectUriVerifier.h in Headers */, - 04A6B6152269383D0035C7C2 /* MSALOauth2FactoryProducer.h in Headers */, + 04A6B6152269383D0035C7C2 /* MSALOauth2ProviderFactory.h in Headers */, B273D082226E850E005A7BB4 /* MSALTokenParameters.h in Headers */, B273D0EE226E8606005A7BB4 /* MSALTokenParameters+Internal.h in Headers */, B273D078226E84DD005A7BB4 /* MSALHTTPConfig.h in Headers */, @@ -1963,7 +2252,6 @@ B273D0B1226E858A005A7BB4 /* MSALErrorConverter.h in Headers */, 04A6B605226938180035C7C2 /* MSALError.h in Headers */, B2472CA6226FDC46008F22AB /* MSALB2CAuthority_Internal.h in Headers */, - 04A6B611226938370035C7C2 /* MSALAuthorityFactory.h in Headers */, 04A6B5DF226937AC0035C7C2 /* MSALAccountsProvider.h in Headers */, 04A6B5F4226937DE0035C7C2 /* MSALAuthority.h in Headers */, B273D0BB226E85A1005A7BB4 /* MSALPublicClientApplicationConfig+Internal.h in Headers */, @@ -1972,7 +2260,6 @@ B273D0BE226E85A5005A7BB4 /* MSALGlobalConfig+Internal.h in Headers */, B273D0A2226E8574005A7BB4 /* MSALIndividualClaimRequest+Internal.h in Headers */, B273D08E226E852F005A7BB4 /* MSALJsonSerializable.h in Headers */, - B273D092226E854C005A7BB4 /* MSALDefaultDispatcher.h in Headers */, B273D08A226E8525005A7BB4 /* MSALIndividualClaimRequest.h in Headers */, 04A6B5FF226938050035C7C2 /* MSALResult.h in Headers */, B273D09E226E856E005A7BB4 /* MSALClaimsRequest+Internal.h in Headers */, @@ -1988,7 +2275,6 @@ buildActionMask = 2147483647; files = ( 04A6B5BF226937520035C7C2 /* MSALAccount+Internal.h in Headers */, - B273D073226E84CF005A7BB4 /* MSALCacheConfig.h in Headers */, B273D0E8226E85FA005A7BB4 /* MSALResult+Internal.h in Headers */, B273D08B226E852A005A7BB4 /* MSALIndividualClaimRequestAdditionalInfo.h in Headers */, 04A6B5BB226937420035C7C2 /* MSALWebviewType_Internal.h in Headers */, @@ -1997,7 +2283,7 @@ B273D071226E84C9005A7BB4 /* MSALSliceConfig.h in Headers */, B273D0E4226E85F2005A7BB4 /* MSALPromptType_Internal.h in Headers */, 04A6B5D0226937810035C7C2 /* MSALRedirectUriVerifier.h in Headers */, - 04A6B6142269383C0035C7C2 /* MSALOauth2FactoryProducer.h in Headers */, + 04A6B6142269383C0035C7C2 /* MSALOauth2ProviderFactory.h in Headers */, B273D0B2226E858A005A7BB4 /* MSALErrorConverter.h in Headers */, B273D0BF226E85A6005A7BB4 /* MSALGlobalConfig+Internal.h in Headers */, B273D067226E84BD005A7BB4 /* MSALPublicClientApplicationConfig.h in Headers */, @@ -2017,7 +2303,7 @@ B273D077226E84DD005A7BB4 /* MSALHTTPConfig.h in Headers */, B273D0CB226E85C7005A7BB4 /* MSALHTTPConfig+Internal.h in Headers */, B273D06F226E84C3005A7BB4 /* MSALGlobalConfig.h in Headers */, - 04A6B5DA2269379C0035C7C2 /* MSALTelemetryDefaultEvent.h in Headers */, + 04A6B5DA2269379C0035C7C2 /* (null) in Headers */, 04A6B5E0226937AD0035C7C2 /* MSALAccountsProvider.h in Headers */, B273D085226E851A005A7BB4 /* MSALInteractiveTokenParameters.h in Headers */, 04A6B5F0226937D00035C7C2 /* MSALB2CAuthority.h in Headers */, @@ -2034,13 +2320,12 @@ B273D09D226E856E005A7BB4 /* MSALClaimsRequest+Internal.h in Headers */, B273D0D1226E85CE005A7BB4 /* MSALTelemetryConfig+Internal.h in Headers */, B273D075226E84D6005A7BB4 /* MSALTelemetryConfig.h in Headers */, + 238BA014227BCAED00A5BACD /* MSALTenantProfile.h in Headers */, 04A6B5F8226937F10035C7C2 /* MSALTelemetry.h in Headers */, 04A6B604226938180035C7C2 /* MSALError.h in Headers */, B2472CA5226FDC46008F22AB /* MSALB2CAuthority_Internal.h in Headers */, B273D081226E850D005A7BB4 /* MSALTokenParameters.h in Headers */, B273D0AB226E8580005A7BB4 /* MSALTelemetryApiId.h in Headers */, - 04A6B610226938360035C7C2 /* MSALAuthorityFactory.h in Headers */, - B273D091226E854C005A7BB4 /* MSALDefaultDispatcher.h in Headers */, B273D0BA226E85A0005A7BB4 /* MSALPublicClientApplicationConfig+Internal.h in Headers */, B273D0D7226E85D6005A7BB4 /* MSALLoggerConfig+Internal.h in Headers */, 04A6B5EE226937CA0035C7C2 /* MSALADFSAuthority.h in Headers */, @@ -2058,26 +2343,34 @@ 96CF952A2268FD0500D97374 /* MSALPublicClientStatusNotifications.h in Headers */, 96CF95292268FD0500D97374 /* MSALRedirectUri.h in Headers */, B273D0AF226E8587005A7BB4 /* MSALErrorConverter+Internal.h in Headers */, - B2B5F08B1FCA61EB00F6AFAD /* MSALTelemetryDefaultEvent.h in Headers */, + B26756D022921C6D000F01D7 /* MSALADFSOauth2Provider.h in Headers */, 1EDAE32C218A4FA0001898E1 /* MSALAuthority_Internal.h in Headers */, 96CF951B2268FD0400D97374 /* MSALLoggerConfig.h in Headers */, + B266391B22B4B84600FEB673 /* NSString+MSALAccountIdenfiers.h in Headers */, 96CF951D2268FD0400D97374 /* MSALDefinitions.h in Headers */, 96CF952E2268FD0500D97374 /* MSALClaimsRequest.h in Headers */, 96CF95262268FD0500D97374 /* MSALADFSAuthority.h in Headers */, 96CF952D2268FD0500D97374 /* MSALInteractiveTokenParameters.h in Headers */, 96B5E6F22256D197002232F9 /* MSALExtraQueryParameters.h in Headers */, 96CF952C2268FD0500D97374 /* MSALSilentTokenParameters.h in Headers */, + B2659C872287D13B00F5A0C3 /* MSALSerializedADALCacheProvider+Internal.h in Headers */, 96CF951C2268FD0400D97374 /* MSAL.h in Headers */, 1EDAE32C218A4FA0001898E1 /* MSALAuthority_Internal.h in Headers */, - B28BDA8E217E9EAB003E5670 /* MSALOauth2FactoryProducer.h in Headers */, + B28BDA8E217E9EAB003E5670 /* MSALOauth2ProviderFactory.h in Headers */, + 6077D4A022498BFF001798A2 /* MSALTenantProfile.h in Headers */, 96CF952F2268FD0500D97374 /* MSALIndividualClaimRequest.h in Headers */, 23576D402252C07700D6F7BA /* MSALClaimsRequest+Internal.h in Headers */, 96CF952B2268FD0500D97374 /* MSALTokenParameters.h in Headers */, 96CF95222268FD0500D97374 /* MSALAccountId.h in Headers */, + B223B0BF22ADFACB00FB8713 /* MSALLegacySharedAccount.h in Headers */, 232D6198224DC44400260C42 /* MSALIndividualClaimRequestAdditionalInfo+Internal.h in Headers */, B273D0D9226E85D8005A7BB4 /* MSALLoggerConfig+Internal.h in Headers */, + B29A56C122826EE00023F5E6 /* MSALSerializedADALCacheProvider.h in Headers */, 96CF95212268FD0400D97374 /* MSALAccount.h in Headers */, + B267569D228F335E000F01D7 /* MSALExternalAccountHandler.h in Headers */, + B26756C422921C42000F01D7 /* MSALAADOauth2Provider.h in Headers */, 232D6195224C62FF00260C42 /* MSALIndividualClaimRequest+Internal.h in Headers */, + B26756BE22921A71000F01D7 /* MSALOauth2Provider.h in Headers */, B273D0E2226E85F1005A7BB4 /* MSALPromptType_Internal.h in Headers */, B21E07B1210E542C007E3A3C /* MSALRedirectUriVerifier.h in Headers */, B273D0D3226E85D0005A7BB4 /* MSALTelemetryConfig+Internal.h in Headers */, @@ -2086,35 +2379,43 @@ B221CEEB20C0AF0B002F5E94 /* MSALAccountId+Internal.h in Headers */, 96CF951A2268FD0400D97374 /* MSALHTTPConfig.h in Headers */, B273D0E6226E85F9005A7BB4 /* MSALResult+Internal.h in Headers */, - 23A68A8D20F57A440071E435 /* MSALAuthorityFactory.h in Headers */, 96CF95152268FD0400D97374 /* MSALPublicClientApplicationConfig.h in Headers */, B2A3C2892145FD0F0082525C /* MSALAccountsProvider.h in Headers */, B273D0B8226E859F005A7BB4 /* MSALPublicClientApplicationConfig+Internal.h in Headers */, 96CF95252268FD0500D97374 /* MSALB2CAuthority.h in Headers */, 96CF95272268FD0500D97374 /* MSALLogger.h in Headers */, + B26756CA22921C5B000F01D7 /* MSALB2COauth2Provider.h in Headers */, 96CF95172268FD0400D97374 /* MSALSliceConfig.h in Headers */, + B227037122A4BA3600030ADC /* MSALLegacySharedAccountsProvider.h in Headers */, 96CF95192268FD0400D97374 /* MSALTelemetryConfig.h in Headers */, 96CF95282268FD0500D97374 /* MSALTelemetry.h in Headers */, B273D0A9226E857F005A7BB4 /* MSALTelemetryApiId.h in Headers */, B273D0CC226E85C8005A7BB4 /* MSALHTTPConfig+Internal.h in Headers */, + B223B0B922ADF8E600FB8713 /* MSALLegacySharedMSAAccount.h in Headers */, B273D0B3226E858B005A7BB4 /* MSALErrorConverter.h in Headers */, + B223B0B322ADF8C500FB8713 /* MSALLegacySharedADALAccount.h in Headers */, 2342584B20649A9800621AFE /* MSALAccount+Internal.h in Headers */, + B26756D522921CC4000F01D7 /* MSALOauth2Provider+Internal.h in Headers */, 96CF95322268FD0500D97374 /* MSALJsonDeserializable.h in Headers */, 96CF95202268FD0400D97374 /* MSALResult.h in Headers */, - B273D093226E854D005A7BB4 /* MSALDefaultDispatcher.h in Headers */, 96CF95182268FD0400D97374 /* MSALCacheConfig.h in Headers */, + B29A56A5228262770023F5E6 /* MSALExternalAccountProviding.h in Headers */, 96CF95242268FD0500D97374 /* MSALAADAuthority.h in Headers */, B2472CA3226FDC46008F22AB /* MSALB2CAuthority_Internal.h in Headers */, + B26756D922922375000F01D7 /* MSALOauth2Authority.h in Headers */, B273D0C1226E85A7005A7BB4 /* MSALGlobalConfig+Internal.h in Headers */, 232D69002240A3FF00594BBD /* MSALTokenParameters+Internal.h in Headers */, B273D0C7226E85C2005A7BB4 /* MSALCacheConfig+Internal.h in Headers */, 96CF95232268FD0500D97374 /* MSALAuthority.h in Headers */, + B27CCDF2229F9F4700CAD565 /* MSALAccountEnumerationParameters.h in Headers */, 963377BF211E14C600943EE0 /* MSALWebviewType_Internal.h in Headers */, + B223B0C522AE215D00FB8713 /* MSALLegacySharedAccountFactory.h in Headers */, B273D0B7226E8597005A7BB4 /* MSALPublicClientApplication+Internal.h in Headers */, 96CF95312268FD0500D97374 /* MSALJsonSerializable.h in Headers */, B273D09B226E856A005A7BB4 /* MSAL_Internal.h in Headers */, 96CF95162268FD0400D97374 /* MSALGlobalConfig.h in Headers */, 96CF951F2268FD0400D97374 /* MSALPublicClientApplication.h in Headers */, + B27CCDE0229F65D700CAD565 /* MSALAccount+MultiTenantAccount.h in Headers */, B203459D21AFA1FB00B221AA /* MSALRedirectUri+Internal.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2124,16 +2425,19 @@ buildActionMask = 2147483647; files = ( 9627C7AE22542EDC0028A859 /* MSALPublicClientApplicationConfig.h in Headers */, + B27CCDF3229F9F4700CAD565 /* MSALAccountEnumerationParameters.h in Headers */, B273D09C226E856B005A7BB4 /* MSAL_Internal.h in Headers */, 9626D14D225828780019417B /* MSALGlobalConfig.h in Headers */, B273D0E7226E85FA005A7BB4 /* MSALResult+Internal.h in Headers */, 96B5E6ED2256D180002232F9 /* MSALSliceConfig.h in Headers */, 96B5E6CF2256D152002232F9 /* MSALCacheConfig.h in Headers */, + B29A56A6228262770023F5E6 /* MSALExternalAccountProviding.h in Headers */, 96B5E6E12256D166002232F9 /* MSALTelemetryConfig.h in Headers */, 96B5E6DB2256D15A002232F9 /* MSALHTTPConfig.h in Headers */, 96B5E6E72256D174002232F9 /* MSALLoggerConfig.h in Headers */, D65A6FA81E3FF3D900C69FBA /* MSAL.h in Headers */, B273D0B4226E858C005A7BB4 /* MSALErrorConverter.h in Headers */, + B26756CB22921C5B000F01D7 /* MSALB2COauth2Provider.h in Headers */, 9682A630218290FE00E37E63 /* MSALDefinitions.h in Headers */, D65A6FA91E3FF3D900C69FBA /* MSALError.h in Headers */, D65A6FAB1E3FF3D900C69FBA /* MSALPublicClientApplication.h in Headers */, @@ -2146,6 +2450,7 @@ 23A68A7520F5386A0071E435 /* MSALAADAuthority.h in Headers */, 23A68A7B20F538B90071E435 /* MSALB2CAuthority.h in Headers */, B273D0D8226E85D7005A7BB4 /* MSALLoggerConfig+Internal.h in Headers */, + B267569E228F335E000F01D7 /* MSALExternalAccountHandler.h in Headers */, B273D0E3226E85F2005A7BB4 /* MSALPromptType_Internal.h in Headers */, 23A68A8120F538DE0071E435 /* MSALADFSAuthority.h in Headers */, D65A6FAA1E3FF3D900C69FBA /* MSALLogger.h in Headers */, @@ -2154,16 +2459,20 @@ B273D0D2226E85D0005A7BB4 /* MSALTelemetryConfig+Internal.h in Headers */, B28BBD342211DC7D00F51723 /* MSALPublicClientStatusNotifications.h in Headers */, 232D68DD223DBA0700594BBD /* MSALInteractiveTokenParameters.h in Headers */, + B26756C522921C42000F01D7 /* MSALAADOauth2Provider.h in Headers */, + B27CCDE1229F65D700CAD565 /* MSALAccount+MultiTenantAccount.h in Headers */, 232D614B2248484C00260C42 /* MSALClaimsRequest.h in Headers */, + B26756D622921CC4000F01D7 /* MSALOauth2Provider+Internal.h in Headers */, 232D68D7223DB8C200594BBD /* MSALSilentTokenParameters.h in Headers */, + B29A56BA228266B40023F5E6 /* MSALSerializedADALCacheProvider.h in Headers */, 232D68CB223DB00500594BBD /* MSALTokenParameters.h in Headers */, 2342584C20649A9800621AFE /* MSALAccount+Internal.h in Headers */, 232D615D22485B4600260C42 /* MSALIndividualClaimRequest.h in Headers */, B203459521AF77FB00B221AA /* MSALRedirectUri.h in Headers */, D62746D31E9B38AF00EFCE99 /* MSALPublicClientApplication+Internal.h in Headers */, - B2B5F08C1FCA61EB00F6AFAD /* MSALTelemetryDefaultEvent.h in Headers */, B273D0B9226E859F005A7BB4 /* MSALPublicClientApplicationConfig+Internal.h in Headers */, B273D0C6226E85C1005A7BB4 /* MSALCacheConfig+Internal.h in Headers */, + B26756BF22921A71000F01D7 /* MSALOauth2Provider.h in Headers */, 96B5E6F32256D197002232F9 /* MSALExtraQueryParameters.h in Headers */, B2472CA4226FDC46008F22AB /* MSALB2CAuthority_Internal.h in Headers */, B21E07B2210E542C007E3A3C /* MSALRedirectUriVerifier.h in Headers */, @@ -2171,13 +2480,15 @@ 23576D412252C07700D6F7BA /* MSALClaimsRequest+Internal.h in Headers */, 232D6199224DC44400260C42 /* MSALIndividualClaimRequestAdditionalInfo+Internal.h in Headers */, 232D6196224C62FF00260C42 /* MSALIndividualClaimRequest+Internal.h in Headers */, - B28BDA8F217E9EAB003E5670 /* MSALOauth2FactoryProducer.h in Headers */, + B28BDA8F217E9EAB003E5670 /* MSALOauth2ProviderFactory.h in Headers */, B221CEEC20C0AF0B002F5E94 /* MSALAccountId+Internal.h in Headers */, + 6077D4A122498BFF001798A2 /* MSALTenantProfile.h in Headers */, + B26756D122921C6D000F01D7 /* MSALADFSOauth2Provider.h in Headers */, B273D0CD226E85C9005A7BB4 /* MSALHTTPConfig+Internal.h in Headers */, + B2659C882287D13B00F5A0C3 /* MSALSerializedADALCacheProvider+Internal.h in Headers */, 232D616322485BA700260C42 /* MSALIndividualClaimRequestAdditionalInfo.h in Headers */, B273D0AA226E8580005A7BB4 /* MSALTelemetryApiId.h in Headers */, - B273D094226E854E005A7BB4 /* MSALDefaultDispatcher.h in Headers */, - 23A68A8E20F57A440071E435 /* MSALAuthorityFactory.h in Headers */, + B26756DA22922375000F01D7 /* MSALOauth2Authority.h in Headers */, 23FB5C1E22542B99002BF1EB /* MSALJsonDeserializable.h in Headers */, 1EDAE331218A4FA2001898E1 /* MSALAuthority_Internal.h in Headers */, B273D0C0226E85A7005A7BB4 /* MSALGlobalConfig+Internal.h in Headers */, @@ -2191,7 +2502,7 @@ /* Begin PBXNativeTarget section */ 04A6B57A226921890035C7C2 /* MSAL (iOS Static Library) */ = { isa = PBXNativeTarget; - buildConfigurationList = 04A6B581226921890035C7C2 /* Build configuration list for PBXNativeTarget "MSAL (iOS Static Library)" */; + buildConfigurationList = 1E5DA69A2272722400B7B816 /* Build configuration list for PBXNativeTarget "MSAL (iOS Static Library)" */; buildPhases = ( 04A6B5BA226937330035C7C2 /* Headers */, 04A6B577226921890035C7C2 /* Sources */, @@ -2209,7 +2520,7 @@ }; 04A6B59B2269286F0035C7C2 /* MSAL (Mac Static Library) */ = { isa = PBXNativeTarget; - buildConfigurationList = 04A6B5A22269286F0035C7C2 /* Build configuration list for PBXNativeTarget "MSAL (Mac Static Library)" */; + buildConfigurationList = 1E5DA69B2272722400B7B816 /* Build configuration list for PBXNativeTarget "MSAL (Mac Static Library)" */; buildPhases = ( 04A6B5982269286F0035C7C2 /* Headers */, 04A6B5992269286F0035C7C2 /* Sources */, @@ -2225,6 +2536,24 @@ productReference = 04A6B59C2269286F0035C7C2 /* libMSAL.a */; productType = "com.apple.product-type.library.static"; }; + 1E614BD922558D8300EBF62F /* MSAL Test App (Mac) */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1E614BEB22558D8300EBF62F /* Build configuration list for PBXNativeTarget "MSAL Test App (Mac)" */; + buildPhases = ( + 1E614BD622558D8300EBF62F /* Sources */, + 1E614BD722558D8300EBF62F /* Frameworks */, + 1E614BD822558D8300EBF62F /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 1EC12C392256BC5400339572 /* PBXTargetDependency */, + ); + name = "MSAL Test App (Mac)"; + productName = MSALMacTestApp; + productReference = 1E614BDA22558D8300EBF62F /* MSAL Test App (Mac).app */; + productType = "com.apple.product-type.application"; + }; 962E37A61E720C5D00DE71FE /* MSAL Test Automation (iOS) */ = { isa = PBXNativeTarget; buildConfigurationList = 962E37B91E720C5D00DE71FE /* Build configuration list for PBXNativeTarget "MSAL Test Automation (iOS)" */; @@ -2244,6 +2573,23 @@ productReference = 962E37BC1E720C5D00DE71FE /* MSAL Test Automation (iOS).app */; productType = "com.apple.product-type.application"; }; + B295A16322D0348400FFB313 /* unit-test-host-mac */ = { + isa = PBXNativeTarget; + buildConfigurationList = B295A17522D0348600FFB313 /* Build configuration list for PBXNativeTarget "unit-test-host-mac" */; + buildPhases = ( + B295A16022D0348400FFB313 /* Sources */, + B295A16122D0348400FFB313 /* Frameworks */, + B295A16222D0348400FFB313 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "unit-test-host-mac"; + productName = "unit-test-host-mac"; + productReference = B295A16422D0348400FFB313 /* unit-test-host-mac.app */; + productType = "com.apple.product-type.application"; + }; B29E2ACD21238F5200B170ED /* MultiAppiOSTests */ = { isa = PBXNativeTarget; buildConfigurationList = B29E2AD521238F5200B170ED /* Build configuration list for PBXNativeTarget "MultiAppiOSTests" */; @@ -2305,23 +2651,6 @@ productReference = D61A64331E5A29580086D120 /* MSAL Test App.app */; productType = "com.apple.product-type.application"; }; - D61A646B1E5AA7120086D120 /* MSAL Test App (Mac) */ = { - isa = PBXNativeTarget; - buildConfigurationList = D61A647A1E5AA7120086D120 /* Build configuration list for PBXNativeTarget "MSAL Test App (Mac)" */; - buildPhases = ( - D61A64681E5AA7120086D120 /* Sources */, - D61A64691E5AA7120086D120 /* Frameworks */, - D61A646A1E5AA7120086D120 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "MSAL Test App (Mac)"; - productName = "MSAL Test App"; - productReference = D61A646C1E5AA7120086D120 /* MSAL Test App.app */; - productType = "com.apple.product-type.application"; - }; D65A6F421E3FD30A00C69FBA /* MSAL (iOS Framework) */ = { isa = PBXNativeTarget; buildConfigurationList = D65A6F481E3FD30A00C69FBA /* Build configuration list for PBXNativeTarget "MSAL (iOS Framework)" */; @@ -2395,6 +2724,7 @@ dependencies = ( 231CE9DB1FEC678400E95D3E /* PBXTargetDependency */, D65A6FD71E3FF49C00C69FBA /* PBXTargetDependency */, + B295A17922D034F400FFB313 /* PBXTargetDependency */, ); name = "MSAL Mac Unit Tests"; productName = "MSAL Mac Unit Tests"; @@ -2435,6 +2765,18 @@ CreatedOnToolsVersion = 10.1; ProvisioningStyle = Automatic; }; + 1E614BD922558D8300EBF62F = { + CreatedOnToolsVersion = 10.1; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Keychain = { + enabled = 0; + }; + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; 962E37A61E720C5D00DE71FE = { DevelopmentTeam = UBF8T346G9; ProvisioningStyle = Automatic; @@ -2444,6 +2786,10 @@ }; }; }; + B295A16322D0348400FFB313 = { + CreatedOnToolsVersion = 10.2; + ProvisioningStyle = Automatic; + }; B29E2ACD21238F5200B170ED = { CreatedOnToolsVersion = 9.4.1; DevelopmentTeam = UBF8T346G9; @@ -2467,10 +2813,6 @@ }; }; }; - D61A646B1E5AA7120086D120 = { - CreatedOnToolsVersion = 8.2.1; - ProvisioningStyle = Automatic; - }; D65A6F421E3FD30A00C69FBA = { CreatedOnToolsVersion = 8.2.1; ProvisioningStyle = Automatic; @@ -2487,6 +2829,7 @@ D65A6FCF1E3FF49C00C69FBA = { CreatedOnToolsVersion = 8.2.1; ProvisioningStyle = Manual; + TestTargetID = B295A16322D0348400FFB313; }; D672279E1EBD111900F3422A = { CreatedOnToolsVersion = 8.3.2; @@ -2524,13 +2867,14 @@ D65A6F4F1E3FD32D00C69FBA /* MSAL (Mac Framework) */, D65A6FCF1E3FF49C00C69FBA /* MSAL Mac Unit Tests */, D61A64321E5A29580086D120 /* MSAL Test App (iOS) */, - D61A646B1E5AA7120086D120 /* MSAL Test App (Mac) */, 962E37A61E720C5D00DE71FE /* MSAL Test Automation (iOS) */, D672279E1EBD111900F3422A /* unit-test-host */, B2BB736F2112C32C000EA4C5 /* InteractiveiOSTests */, B29E2ACD21238F5200B170ED /* MultiAppiOSTests */, + 1E614BD922558D8300EBF62F /* MSAL Test App (Mac) */, 04A6B57A226921890035C7C2 /* MSAL (iOS Static Library) */, 04A6B59B2269286F0035C7C2 /* MSAL (Mac Static Library) */, + B295A16322D0348400FFB313 /* unit-test-host-mac */, ); }; /* End PBXProject section */ @@ -2616,6 +2960,15 @@ /* End PBXReferenceProxy section */ /* Begin PBXResourcesBuildPhase section */ + 1E614BD822558D8300EBF62F /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1E614BE322558D8300EBF62F /* Assets.xcassets in Resources */, + 1E614BE622558D8300EBF62F /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 962E37B71E720C5D00DE71FE /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -2626,32 +2979,34 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - B29E2ACC21238F5200B170ED /* Resources */ = { + B295A16222D0348400FFB313 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + B295A16D22D0348600FFB313 /* Assets.xcassets in Resources */, + B295A17022D0348600FFB313 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; - B2BB736E2112C32C000EA4C5 /* Resources */ = { + B29E2ACC21238F5200B170ED /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - D61A64311E5A29580086D120 /* Resources */ = { + B2BB736E2112C32C000EA4C5 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - D61A64B91E5ADBE80086D120 /* Images.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; - D61A646A1E5AA7120086D120 /* Resources */ = { + D61A64311E5A29580086D120 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + D61A64B91E5ADBE80086D120 /* Images.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2736,7 +3091,6 @@ B273D0E0226E85E3005A7BB4 /* MSALExtraQueryParameters.m in Sources */, 04A6B5C1226937590035C7C2 /* MSALResult.m in Sources */, 04A6B60F226938340035C7C2 /* MSALADFSAuthority.m in Sources */, - 04A6B612226938390035C7C2 /* MSALAuthorityFactory.m in Sources */, B273D0F0226E8609005A7BB4 /* MSALTokenParameters.m in Sources */, B273D0F1226E860B005A7BB4 /* MSALInteractiveTokenParameters.m in Sources */, 04A6B5B5226937080035C7C2 /* MSALWebviewType.m in Sources */, @@ -2744,18 +3098,17 @@ 04A6B5B4226937080035C7C2 /* MSALPromptType.m in Sources */, 04A6B5BD2269374D0035C7C2 /* MSALAccount.m in Sources */, 04A6B6092269382B0035C7C2 /* MSALAuthority.m in Sources */, - 04A6B6162269383F0035C7C2 /* MSALOauth2FactoryProducer.m in Sources */, + 04A6B6162269383F0035C7C2 /* MSALOauth2ProviderFactory.m in Sources */, 04A6B5C92269376A0035C7C2 /* MSALErrorConverter.m in Sources */, B273D0DC226E85DD005A7BB4 /* MSALSliceConfig.m in Sources */, 04A6B60B2269382E0035C7C2 /* MSALAADAuthority.m in Sources */, - 04A6B5D8226937990035C7C2 /* MSALTelemetryDefaultEvent.m in Sources */, + 04A6B5D8226937990035C7C2 /* (null) in Sources */, B273D0A7226E857B005A7BB4 /* MSALIndividualClaimRequestAdditionalInfo.m in Sources */, 04A6B5AE226936F30035C7C2 /* MSALFramework.m in Sources */, B273D0C3226E85AA005A7BB4 /* MSALGlobalConfig.m in Sources */, B273D0DA226E85DB005A7BB4 /* MSALLoggerConfig.m in Sources */, B273D0CF226E85CC005A7BB4 /* MSALHTTPConfig.m in Sources */, 04A6B5D1226937850035C7C2 /* MSALRedirectUriVerifier.m in Sources */, - 04A6B5D42269378F0035C7C2 /* MSALDefaultDispatcher.m in Sources */, 04A6B5B72269371E0035C7C2 /* MSALAccountId.m in Sources */, B273D095226E855B005A7BB4 /* MSALRedirectUri.m in Sources */, 04A6B5C7226937660035C7C2 /* MSALLogger.m in Sources */, @@ -2781,7 +3134,6 @@ B273D0E1226E85E3005A7BB4 /* MSALExtraQueryParameters.m in Sources */, 04A6B5C2226937590035C7C2 /* MSALResult.m in Sources */, 04A6B60E226938330035C7C2 /* MSALADFSAuthority.m in Sources */, - 04A6B6132269383A0035C7C2 /* MSALAuthorityFactory.m in Sources */, B273D0EF226E8609005A7BB4 /* MSALTokenParameters.m in Sources */, B273D0F2226E860B005A7BB4 /* MSALInteractiveTokenParameters.m in Sources */, 04A6B5B3226937070035C7C2 /* MSALWebviewType.m in Sources */, @@ -2789,18 +3141,17 @@ 04A6B5B2226937070035C7C2 /* MSALPromptType.m in Sources */, 04A6B5BE2269374E0035C7C2 /* MSALAccount.m in Sources */, 04A6B6082269382A0035C7C2 /* MSALAuthority.m in Sources */, - 04A6B6172269383F0035C7C2 /* MSALOauth2FactoryProducer.m in Sources */, + 04A6B6172269383F0035C7C2 /* MSALOauth2ProviderFactory.m in Sources */, 04A6B5C8226937690035C7C2 /* MSALErrorConverter.m in Sources */, B273D0DD226E85DD005A7BB4 /* MSALSliceConfig.m in Sources */, 04A6B60A2269382D0035C7C2 /* MSALAADAuthority.m in Sources */, - 04A6B5D7226937980035C7C2 /* MSALTelemetryDefaultEvent.m in Sources */, + 04A6B5D7226937980035C7C2 /* (null) in Sources */, B273D0A8226E857C005A7BB4 /* MSALIndividualClaimRequestAdditionalInfo.m in Sources */, 04A6B5AF226936F40035C7C2 /* MSALFramework.m in Sources */, B273D0C2226E85AA005A7BB4 /* MSALGlobalConfig.m in Sources */, B273D0DB226E85DB005A7BB4 /* MSALLoggerConfig.m in Sources */, B273D0CE226E85CC005A7BB4 /* MSALHTTPConfig.m in Sources */, 04A6B5D2226937890035C7C2 /* MSALRedirectUriVerifier.m in Sources */, - 04A6B5D32269378E0035C7C2 /* MSALDefaultDispatcher.m in Sources */, 04A6B5B82269371F0035C7C2 /* MSALAccountId.m in Sources */, B273D096226E855C005A7BB4 /* MSALRedirectUri.m in Sources */, 04A6B5C6226937650035C7C2 /* MSALLogger.m in Sources */, @@ -2819,6 +3170,19 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 1E614BD622558D8300EBF62F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1E8B0031225E94A3006BB8BD /* MSALCacheViewController.m in Sources */, + 1E1A2E042256D12F001009ED /* MSALTestAppSettings.m in Sources */, + 1EC12C112255DB9200339572 /* MSALAcquireTokenViewController.m in Sources */, + 1E4522AD22581B8A00D27CA7 /* MSALScopesViewController.m in Sources */, + 1E614BE922558D8300EBF62F /* main.m in Sources */, + 1E614BDE22558D8300EBF62F /* MSALAppDelegate.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 962E37A91E720C5D00DE71FE /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -2839,6 +3203,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + B295A16022D0348400FFB313 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B295A16B22D0348400FFB313 /* ViewController.m in Sources */, + B295A17322D0348600FFB313 /* main.m in Sources */, + B295A16822D0348400FFB313 /* AppDelegate.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; B29E2ACA21238F5200B170ED /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -2896,7 +3270,6 @@ D61A64941E5AA7D60086D120 /* MSALTestAppDelegate.m in Sources */, 1EB7ABD621262C420058C7E0 /* MSALTestAppAuthorityTypeViewController.m in Sources */, D61A64B11E5AAC5C0086D120 /* MSALTestAppSettings.m in Sources */, - B2AD634D1EA5665F00EFEEF1 /* MSALTestAppTelemetryDispatcher.m in Sources */, D659D4EF1E64BEA3007FBCF7 /* MSALTestAppSettingViewController.m in Sources */, 96CFA00B1E6E3460003BFCDC /* MSALTestAppScopesViewController.m in Sources */, B277241E1EAE97D700375C53 /* MSALStressTestHelper.m in Sources */, @@ -2910,57 +3283,60 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - D61A64681E5AA7120086D120 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - D61A64B21E5AAC5C0086D120 /* MSALTestAppSettings.m in Sources */, - D61A64971E5AA7E20086D120 /* main.m in Sources */, - D61A64981E5AA7E20086D120 /* MSALTestAppDelegate.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; D65A6F3E1E3FD30A00C69FBA /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + B223B0B522ADF8C500FB8713 /* MSALLegacySharedADALAccount.m in Sources */, + B267569F228F335E000F01D7 /* MSALExternalAccountHandler.m in Sources */, 232D68CC223DB00500594BBD /* MSALTokenParameters.m in Sources */, 9626D14E225828780019417B /* MSALGlobalConfig.m in Sources */, 96B5E6DC2256D15A002232F9 /* MSALHTTPConfig.m in Sources */, 9627C7AF22542EDC0028A859 /* MSALPublicClientApplicationConfig.m in Sources */, D61F5BCA1E59359900912CB8 /* MSALFramework.m in Sources */, + B26756DB22922375000F01D7 /* MSALOauth2Authority.m in Sources */, 96B5E6E82256D174002232F9 /* MSALLoggerConfig.m in Sources */, B221CEDD20C0AC60002F5E94 /* MSALAccountId.m in Sources */, 04D32CAE1FD615B3000B123E /* MSALErrorConverter.m in Sources */, + B26756D222921C6D000F01D7 /* MSALADFSOauth2Provider.m in Sources */, 232D614C2248484C00260C42 /* MSALClaimsRequest.m in Sources */, B203459621AF77FB00B221AA /* MSALRedirectUri.m in Sources */, 23A68A7620F5386A0071E435 /* MSALAADAuthority.m in Sources */, + 233E96FD22653EFC007FCE2A /* MSALTelemetryEventsObservingProxy.m in Sources */, 23A68A7C20F538B90071E435 /* MSALB2CAuthority.m in Sources */, + 6077D4A922498D87001798A2 /* MSALTenantProfile.m in Sources */, + B223B0C022ADFACB00FB8713 /* MSALLegacySharedAccount.m in Sources */, D61BD2AF1EBD09F90007E484 /* MSALLogger.m in Sources */, - D61BD2BF1EBD0A010007E484 /* MSALDefaultDispatcher.m in Sources */, - B28BDA90217E9EAB003E5670 /* MSALOauth2FactoryProducer.m in Sources */, + B28BDA90217E9EAB003E5670 /* MSALOauth2ProviderFactory.m in Sources */, D61BD2B01EBD09F90007E484 /* MSALPublicClientApplication.m in Sources */, D61BD2AD1EBD09F90007E484 /* MSALError.m in Sources */, 96B5E6F42256D197002232F9 /* MSALExtraQueryParameters.m in Sources */, + B223B0C622AE215D00FB8713 /* MSALLegacySharedAccountFactory.m in Sources */, + B26756CC22921C5B000F01D7 /* MSALB2COauth2Provider.m in Sources */, 96B5E6E22256D166002232F9 /* MSALTelemetryConfig.m in Sources */, 963377C1211E14C600943EE0 /* MSALWebviewType.m in Sources */, + B27CCDF4229F9F4700CAD565 /* MSALAccountEnumerationParameters.m in Sources */, + B227037322A4BA3E00030ADC /* MSALLegacySharedAccountsProvider.m in Sources */, 232D616422485BA700260C42 /* MSALIndividualClaimRequestAdditionalInfo.m in Sources */, D61BD2BD1EBD0A010007E484 /* MSALTelemetry.m in Sources */, D61BD2B11EBD09F90007E484 /* MSALResult.m in Sources */, 232D615E22485B4600260C42 /* MSALIndividualClaimRequest.m in Sources */, + B26756C022921A71000F01D7 /* MSALOauth2Provider.m in Sources */, D61BD2C91EBD0A0F0007E484 /* MSALAuthority.m in Sources */, D61BD2B21EBD09F90007E484 /* MSALAccount.m in Sources */, + B266391C22B4B84600FEB673 /* NSString+MSALAccountIdenfiers.m in Sources */, 96B5E6D02256D152002232F9 /* MSALCacheConfig.m in Sources */, 232D68DE223DBA0700594BBD /* MSALInteractiveTokenParameters.m in Sources */, B2C17B0A1FC8DB2E0070A514 /* MSIDVersion.m in Sources */, + B26756C622921C42000F01D7 /* MSALAADOauth2Provider.m in Sources */, D61BD2B31EBD09F90007E484 /* MSALPromptType.m in Sources */, B28BBD352211DC7D00F51723 /* MSALPublicClientStatusNotifications.m in Sources */, - 23A68A8F20F57A440071E435 /* MSALAuthorityFactory.m in Sources */, 23A68A8220F538DE0071E435 /* MSALADFSAuthority.m in Sources */, - B2B5F08D1FCA61EB00F6AFAD /* MSALTelemetryDefaultEvent.m in Sources */, + B29A56C222826EE20023F5E6 /* MSALSerializedADALCacheProvider.m in Sources */, B21E07B3210E542C007E3A3C /* MSALRedirectUriVerifier.m in Sources */, 96B5E6EE2256D180002232F9 /* MSALSliceConfig.m in Sources */, B2A3C28B2145FD0F0082525C /* MSALAccountsProvider.m in Sources */, + B223B0BA22ADF8E600FB8713 /* MSALLegacySharedMSAAccount.m in Sources */, 232D68D8223DB8C200594BBD /* MSALSilentTokenParameters.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2974,34 +3350,41 @@ 96B5E6DD2256D15A002232F9 /* MSALHTTPConfig.m in Sources */, 9627C7B022542EDC0028A859 /* MSALPublicClientApplicationConfig.m in Sources */, D65A6FA31E3FF3D900C69FBA /* MSALAccount.m in Sources */, + B26756DC22922375000F01D7 /* MSALOauth2Authority.m in Sources */, 96B5E6E92256D174002232F9 /* MSALLoggerConfig.m in Sources */, D61F5BCB1E59359900912CB8 /* MSALFramework.m in Sources */, B21E07BE210E5458007E3A3C /* MSALRedirectUriVerifier.m in Sources */, + B26756D322921C6D000F01D7 /* MSALADFSOauth2Provider.m in Sources */, 232D614D2248484C00260C42 /* MSALClaimsRequest.m in Sources */, B203459721AF77FC00B221AA /* MSALRedirectUri.m in Sources */, D69ADB1C1E50531300952049 /* MSALPromptType.m in Sources */, + 233E96FE22653EFC007FCE2A /* MSALTelemetryEventsObservingProxy.m in Sources */, 96D9A54A1E4AB23100674A85 /* MSALTelemetry.m in Sources */, - E023970B1E7B1C4B004D6278 /* MSALDefaultDispatcher.m in Sources */, + 6077D4AA22498D87001798A2 /* MSALTenantProfile.m in Sources */, + B26756A0228F335E000F01D7 /* MSALExternalAccountHandler.m in Sources */, D673F08F1E4CE6D70018BA91 /* MSALError.m in Sources */, 23A68A8320F538DE0071E435 /* MSALADFSAuthority.m in Sources */, 23A68A7720F5386A0071E435 /* MSALAADAuthority.m in Sources */, - B28BDA91217E9EAB003E5670 /* MSALOauth2FactoryProducer.m in Sources */, + B28BDA91217E9EAB003E5670 /* MSALOauth2ProviderFactory.m in Sources */, 96B5E6F52256D197002232F9 /* MSALExtraQueryParameters.m in Sources */, + B26756CD22921C5B000F01D7 /* MSALB2COauth2Provider.m in Sources */, 96B5E6E32256D166002232F9 /* MSALTelemetryConfig.m in Sources */, D673F0911E4CE6D70018BA91 /* MSALLogger.m in Sources */, + B29A56BB228266B40023F5E6 /* MSALSerializedADALCacheProvider.m in Sources */, + B27CCDF5229F9F4700CAD565 /* MSALAccountEnumerationParameters.m in Sources */, 232D616522485BA700260C42 /* MSALIndividualClaimRequestAdditionalInfo.m in Sources */, 963377C2211E14C600943EE0 /* MSALWebviewType.m in Sources */, B221CEDE20C0AC60002F5E94 /* MSALAccountId.m in Sources */, 232D615F22485B4600260C42 /* MSALIndividualClaimRequest.m in Sources */, + B26756C122921A71000F01D7 /* MSALOauth2Provider.m in Sources */, D673F0921E4CE6D70018BA91 /* MSALPublicClientApplication.m in Sources */, B2C17B0B1FC8DB2E0070A514 /* MSIDVersion.m in Sources */, 96B5E6D12256D152002232F9 /* MSALCacheConfig.m in Sources */, 232D68DF223DBA0700594BBD /* MSALInteractiveTokenParameters.m in Sources */, 94E876CE1E492D6000FB96ED /* MSALAuthority.m in Sources */, + B26756C722921C42000F01D7 /* MSALAADOauth2Provider.m in Sources */, 04D32CAF1FD615B3000B123E /* MSALErrorConverter.m in Sources */, B28BBD362211DC7D00F51723 /* MSALPublicClientStatusNotifications.m in Sources */, - B2B5F08E1FCA61EB00F6AFAD /* MSALTelemetryDefaultEvent.m in Sources */, - 23A68A9020F57A440071E435 /* MSALAuthorityFactory.m in Sources */, D673F0931E4CE6D70018BA91 /* MSALResult.m in Sources */, 23A68A7D20F538B90071E435 /* MSALB2CAuthority.m in Sources */, 96B5E6EF2256D180002232F9 /* MSALSliceConfig.m in Sources */, @@ -3017,26 +3400,36 @@ 23A169B52073325500B051F3 /* MSALPublicClientApplicationTests.m in Sources */, D61F5BC01E5913BE00912CB8 /* SFSafariViewController+TestOverrides.m in Sources */, D69ADB351E516F9B00952049 /* MSALTestBundle.m in Sources */, + B2725ED022C04689009B454A /* MSALLegacySharedAccountFactoryTests.m in Sources */, D69ADB3F1E516F9B00952049 /* MSALTestURLSessionDataTask.m in Sources */, B256121B217EA44900999876 /* MSALOauth2FactoryProducerTests.m in Sources */, - D62746D91E9B5F1E00EFCE99 /* MSALUserTests.m in Sources */, + D62746D91E9B5F1E00EFCE99 /* MSALAccountTests.m in Sources */, D69ADB3D1E516F9B00952049 /* MSIDTestURLSession+MSAL.m in Sources */, 2364C74B1FB3E5CB00835428 /* XCTestCase+HelperMethods.m in Sources */, + B2725EB522BF2774009B454A /* MSALPublicClientApplicationAccountUpdateTests.m in Sources */, + B2725ECC22C0466E009B454A /* MSALLegacySharedADALAccountTests.m in Sources */, 23F32F0C1FF4789100B2905E /* MSIDTestURLResponse+MSAL.m in Sources */, B21E07C0210E56DD007E3A3C /* MSALRedirectUriVerifierTests.m in Sources */, D61F5BC31E59193500912CB8 /* MSALFakeViewController.m in Sources */, 04D32CD01FD8AFF3000B123E /* MSALErrorConverterTests.m in Sources */, - E02396FD1E7B0E20004D6278 /* MSALTelemetryDispatcherTests.m in Sources */, + B2725E7F22BD88BE009B454A /* NSStringAccountIdentifiersTest.m in Sources */, + B2725EC522BF4865009B454A /* MSALMockExternalAccountHandler.m in Sources */, 23A169B420732F3A00B051F3 /* MSALB2CPolicyTests.m in Sources */, D69ADB371E516F9B00952049 /* MSALTestCase.m in Sources */, + B2725ECE22C04679009B454A /* MSALLegacySharedMSAAccountTests.m in Sources */, + 233E970B226571AB007FCE2A /* MSALTelemetryAggregatedTests.m in Sources */, + B2725ECA22C04661009B454A /* MSALLegacySharedAccountTests.m in Sources */, 23A68A9320F59E6B0071E435 /* NSString+MSALTestUtil.m in Sources */, 1E8FC6A3221F370C00B4D4C1 /* MSALResultTests.m in Sources */, + B2ADD76E22C08B6A0093FD43 /* MSALLegacySharedAccountTestUtil.m in Sources */, 960751BB2183E82C00F2BF2F /* MSALAccountIdTests.m in Sources */, - 23CDA9B31FA45A9E00FDD5C0 /* MSALTelemetryTests.m in Sources */, - E02396FB1E7B005C004D6278 /* MSALTelemetryTestDispatcher.m in Sources */, + B2725ED222C0469A009B454A /* MSALLegacySharedAccountsProviderTests.m in Sources */, + 609AF9332256BD0C00E2978D /* MSALAccountsProviderTests.m in Sources */, + B2725EAC22BF2759009B454A /* MSALExternalAccountHandlerTests.m in Sources */, 232D6192224C53E500260C42 /* MSALClaimsRequestTests.m in Sources */, B281B33B226BC225009619AB /* MSALPublicClientApplicationConfigTests.m in Sources */, D6B58A541EB2C4A8000B3A5F /* MSALAcquireTokenTests.m in Sources */, + B29A56D52283D7430023F5E6 /* MSALAADAuthorityTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3044,11 +3437,15 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + B2725EAD22BF2759009B454A /* MSALExternalAccountHandlerTests.m in Sources */, + B2725EB622BF2774009B454A /* MSALPublicClientApplicationAccountUpdateTests.m in Sources */, 23A68A9420F59E6B0071E435 /* NSString+MSALTestUtil.m in Sources */, 23F32F0D1FF4789200B2905E /* MSIDTestURLResponse+MSAL.m in Sources */, + B2725EC622BF4865009B454A /* MSALMockExternalAccountHandler.m in Sources */, D69ADB401E516F9B00952049 /* MSALTestURLSessionDataTask.m in Sources */, - D62746DA1E9B5F1E00EFCE99 /* MSALUserTests.m in Sources */, + D62746DA1E9B5F1E00EFCE99 /* MSALAccountTests.m in Sources */, B256121C217EA44900999876 /* MSALOauth2FactoryProducerTests.m in Sources */, + B29A56D62283D7430023F5E6 /* MSALAADAuthorityTests.m in Sources */, D69ADB381E516F9B00952049 /* MSALTestCase.m in Sources */, 04D32CD11FD8AFF3000B123E /* MSALErrorConverterTests.m in Sources */, 232D6193224C53E500260C42 /* MSALClaimsRequestTests.m in Sources */, @@ -3059,6 +3456,7 @@ B2D6672D210E766F00952595 /* MSALPublicClientApplicationTests.m in Sources */, 1E8FC6A4221F370C00B4D4C1 /* MSALResultTests.m in Sources */, 2364C74C1FB3E5CC00835428 /* XCTestCase+HelperMethods.m in Sources */, + 233E970C226571AC007FCE2A /* MSALTelemetryAggregatedTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3085,6 +3483,11 @@ name = "IdentityCore Mac"; targetProxy = 04A6B5AC226935190035C7C2 /* PBXContainerItemProxy */; }; + 1EC12C392256BC5400339572 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D65A6F4F1E3FD32D00C69FBA /* MSAL (Mac Framework) */; + targetProxy = 1EC12C382256BC5400339572 /* PBXContainerItemProxy */; + }; 231CE9D91FEC677D00E95D3E /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = "IdentityTest iOS"; @@ -3105,6 +3508,11 @@ name = "IdentityLabAutomation iOS"; targetProxy = B21FA9C22204DCB200806B68 /* PBXContainerItemProxy */; }; + B295A17922D034F400FFB313 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B295A16322D0348400FFB313 /* unit-test-host-mac */; + targetProxy = B295A17822D034F400FFB313 /* PBXContainerItemProxy */; + }; B29E2AD421238F5200B170ED /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 962E37A61E720C5D00DE71FE /* MSAL Test Automation (iOS) */; @@ -3163,12 +3571,20 @@ /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ - D61A64911E5AA7C60086D120 /* MainMenu.xib */ = { + 1E614BE422558D8300EBF62F /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 1E614BE522558D8300EBF62F /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + B295A16E22D0348600FFB313 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( - D61A64921E5AA7C60086D120 /* Base */, + B295A16F22D0348600FFB313 /* Base */, ); - name = MainMenu.xib; + name = Main.storyboard; sourceTree = ""; }; D67227AA1EBD111900F3422A /* Main.storyboard */ = { @@ -3190,41 +3606,168 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ - 04A6B582226921890035C7C2 /* Debug */ = { + 1E5DA690227271BF00B7B816 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 04A6B584226921CD0035C7C2 /* msal__static__lib__ios.xcconfig */; buildSettings = { - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + PRODUCT_NAME = "MSAL (iOS Static Library)"; }; name = Debug; }; - 04A6B583226921890035C7C2 /* Release */ = { + 1E5DA691227271BF00B7B816 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 04A6B584226921CD0035C7C2 /* msal__static__lib__ios.xcconfig */; buildSettings = { - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + PRODUCT_NAME = "MSAL (iOS Static Library)"; }; name = Release; }; - 04A6B5A32269286F0035C7C2 /* Debug */ = { + 1E5DA692227271BF00B7B816 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 04A6B585226921CD0035C7C2 /* msal__static__lib__mac.xcconfig */; buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; - MACOSX_DEPLOYMENT_TARGET = 10.11; + PRODUCT_NAME = "MSAL (macOS Static Library)"; }; name = Debug; }; - 04A6B5A42269286F0035C7C2 /* Release */ = { + 1E5DA693227271BF00B7B816 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 04A6B585226921CD0035C7C2 /* msal__static__lib__mac.xcconfig */; buildSettings = { - MACOSX_DEPLOYMENT_TARGET = 10.11; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + PRODUCT_NAME = "MSAL (macOS Static Library)"; + }; + name = Release; + }; + 1E614BEC22558D8300EBF62F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = test/app/mac/MSALMacTestApp.entitlements; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = ""; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = "$(SRCROOT)/test/app/mac/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.MSALMacTestApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SDKROOT = macosx; + USER_HEADER_SEARCH_PATHS = "$(inherited) $IDCORE_PATH/src/** $(HOME)/aadoverrides"; + }; + name = Debug; + }; + 1E614BED22558D8300EBF62F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = test/app/mac/MSALMacTestApp.entitlements; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = ""; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = "$(SRCROOT)/test/app/mac/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.microsoft.MSALMacTestApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SDKROOT = macosx; + USER_HEADER_SEARCH_PATHS = "$(inherited) $IDCORE_PATH/src/** $(HOME)/aadoverrides"; }; name = Release; }; @@ -3263,6 +3806,127 @@ }; name = Release; }; + B295A17622D0348600FFB313 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = ""; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = "$(SRCROOT)/test/unit/mac/unit-test-host/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = "com.microsoft.unit-test-host"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + B295A17722D0348600FFB313 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = ""; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = "$(SRCROOT)/test/unit/mac/unit-test-host/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = "com.microsoft.unit-test-host"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; B29E2AD621238F5200B170ED /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = B2BB73962112C4B3000EA4C5 /* msal__ui_test__ios.xcconfig */; @@ -3528,6 +4192,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = D61A64661E5AA6B40086D120 /* msal__test_app__ios.xcconfig */; buildSettings = { + CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO; CODE_SIGN_ENTITLEMENTS = "MSAL Test App.entitlements"; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -3544,6 +4209,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = D61A64661E5AA6B40086D120 /* msal__test_app__ios.xcconfig */; buildSettings = { + CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO; CODE_SIGN_ENTITLEMENTS = "MSAL Test App.entitlements"; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -3555,24 +4221,6 @@ }; name = Release; }; - D61A647B1E5AA7120086D120 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = D61A64671E5AA6BE0086D120 /* msal__test_app__mac.xcconfig */; - buildSettings = { - DEVELOPMENT_TEAM = ""; - MACOSX_DEPLOYMENT_TARGET = 10.11; - }; - name = Debug; - }; - D61A647C1E5AA7120086D120 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = D61A64671E5AA6BE0086D120 /* msal__test_app__mac.xcconfig */; - buildSettings = { - DEVELOPMENT_TEAM = ""; - MACOSX_DEPLOYMENT_TARGET = 10.11; - }; - name = Release; - }; D65A6F491E3FD30A00C69FBA /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = D65A6FE71E40002800C69FBA /* msal__framework__ios.xcconfig */; @@ -3654,6 +4302,7 @@ DEVELOPMENT_TEAM = ""; GCC_OPTIMIZATION_LEVEL = 0; PROVISIONING_PROFILE_SPECIFIER = ""; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/unit-test-host-mac.app/Contents/MacOS/unit-test-host-mac"; USER_HEADER_SEARCH_PATHS = "$(inherited) $IDCORE_PATH/src/** $IDCORE_PATH/tests/util/** $IDCORE_PATH/tests/mocks/**"; }; name = Debug; @@ -3665,6 +4314,7 @@ CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = ""; PROVISIONING_PROFILE_SPECIFIER = ""; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/unit-test-host-mac.app/Contents/MacOS/unit-test-host-mac"; USER_HEADER_SEARCH_PATHS = "$(inherited) $IDCORE_PATH/src/** $IDCORE_PATH/tests/util/** $IDCORE_PATH/tests/mocks/**"; }; name = Release; @@ -3712,20 +4362,29 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 04A6B581226921890035C7C2 /* Build configuration list for PBXNativeTarget "MSAL (iOS Static Library)" */ = { + 1E5DA69A2272722400B7B816 /* Build configuration list for PBXNativeTarget "MSAL (iOS Static Library)" */ = { isa = XCConfigurationList; buildConfigurations = ( - 04A6B582226921890035C7C2 /* Debug */, - 04A6B583226921890035C7C2 /* Release */, + 1E5DA690227271BF00B7B816 /* Debug */, + 1E5DA691227271BF00B7B816 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 04A6B5A22269286F0035C7C2 /* Build configuration list for PBXNativeTarget "MSAL (Mac Static Library)" */ = { + 1E5DA69B2272722400B7B816 /* Build configuration list for PBXNativeTarget "MSAL (Mac Static Library)" */ = { isa = XCConfigurationList; buildConfigurations = ( - 04A6B5A32269286F0035C7C2 /* Debug */, - 04A6B5A42269286F0035C7C2 /* Release */, + 1E5DA692227271BF00B7B816 /* Debug */, + 1E5DA693227271BF00B7B816 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1E614BEB22558D8300EBF62F /* Build configuration list for PBXNativeTarget "MSAL Test App (Mac)" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1E614BEC22558D8300EBF62F /* Debug */, + 1E614BED22558D8300EBF62F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -3739,6 +4398,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + B295A17522D0348600FFB313 /* Build configuration list for PBXNativeTarget "unit-test-host-mac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B295A17622D0348600FFB313 /* Debug */, + B295A17722D0348600FFB313 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; B29E2AD521238F5200B170ED /* Build configuration list for PBXNativeTarget "MultiAppiOSTests" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -3766,15 +4434,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - D61A647A1E5AA7120086D120 /* Build configuration list for PBXNativeTarget "MSAL Test App (Mac)" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - D61A647B1E5AA7120086D120 /* Debug */, - D61A647C1E5AA7120086D120 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; D65A6F481E3FD30A00C69FBA /* Build configuration list for PBXNativeTarget "MSAL (iOS Framework)" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/MSAL/MSAL.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/MSAL/MSAL.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/MSAL/MSAL.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/MSAL (Mac Static Library).xcscheme b/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/MSAL (Mac Static Library).xcscheme index 7297893b61..d155f8bae1 100644 --- a/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/MSAL (Mac Static Library).xcscheme +++ b/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/MSAL (Mac Static Library).xcscheme @@ -15,7 +15,7 @@ @@ -46,7 +46,7 @@ @@ -64,7 +64,7 @@ diff --git a/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/MSAL (iOS Static Library).xcscheme b/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/MSAL (iOS Static Library).xcscheme index e42e5acd67..f68ba05008 100644 --- a/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/MSAL (iOS Static Library).xcscheme +++ b/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/MSAL (iOS Static Library).xcscheme @@ -15,7 +15,7 @@ @@ -46,7 +46,7 @@ @@ -64,7 +64,7 @@ diff --git a/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/MSAL Test App (Mac).xcscheme b/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/MSAL Test App (Mac).xcscheme index 6c4bf914f7..16e36a5afb 100644 --- a/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/MSAL Test App (Mac).xcscheme +++ b/MSAL/MSAL.xcodeproj/xcshareddata/xcschemes/MSAL Test App (Mac).xcscheme @@ -1,6 +1,6 @@ @@ -32,8 +32,8 @@ @@ -55,8 +55,8 @@ runnableDebuggingMode = "0"> @@ -74,8 +74,8 @@ runnableDebuggingMode = "0"> diff --git a/MSAL/resources/ios/Info.plist b/MSAL/resources/ios/Info.plist index 0353c75717..399882e178 100644 --- a/MSAL/resources/ios/Info.plist +++ b/MSAL/resources/ios/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 0.4.3 + 0.5.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass diff --git a/MSAL/resources/mac/Info.plist b/MSAL/resources/mac/Info.plist index c9c881ed64..54496eb6b1 100644 --- a/MSAL/resources/mac/Info.plist +++ b/MSAL/resources/mac/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 0.4.3 + 0.5.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright diff --git a/MSAL/src/MSALAccount+Internal.h b/MSAL/src/MSALAccount+Internal.h index 4c0f824cf5..6255e31ecc 100644 --- a/MSAL/src/MSALAccount+Internal.h +++ b/MSAL/src/MSALAccount+Internal.h @@ -26,53 +26,41 @@ //------------------------------------------------------------------------------ #import "MSALAccount.h" +#import "MSALTenantProfile+Internal.h" @class MSIDAccountIdentifier; @class MSIDAADV2IdTokenClaims; @class MSIDClientInfo; @class MSIDAccount; @class MSALAccountId; +@class MSIDIdTokenClaims; +@protocol MSALAccount; +@class MSALOauth2Provider; @interface MSALAccount () +@property (nonatomic) MSALAccountId *homeAccountId; +@property (nonatomic) NSString *username; +@property (nonatomic) NSString *environment; +@property (nonatomic) NSMutableArray *mTenantProfiles; +@property (nonatomic) NSDictionary *accountClaims; +@property (nonatomic) NSString *identifier; @property (nonatomic) MSIDAccountIdentifier *lookupAccountIdentifier; -/* TODO: These properties will be public once we agree on having an account per tenant. - For now, will keep them here. - */ - -/*! - Account identifier for the target tenant - */ -@property (nonatomic) MSALAccountId *localAccountId; - -/*! - The displayable name of the account. Can be nil if not returned by the service. - */ -@property (nonatomic) NSString *name; - - -/*! - Initialize an MSALAccount with given information - - @param username The username value in UserPrincipleName(UPN) format - @param name The given name of the user - @param homeAccountId Unique identifier of the account in the home directory - @param localAccountId Unique identifier of the account in the signed in directory. - @param environment Host part of the authority string - @param tenantId An identifier for the tenant that the account was acquired from - */ -- (id)initWithUsername:(NSString *)username - name:(NSString *)name - homeAccountId:(NSString *)homeAccountId - localAccountId:(NSString *)localAccountId - environment:(NSString *)environment - tenantId:(NSString *)tenantId; +- (instancetype)initWithUsername:(NSString *)username + homeAccountId:(MSALAccountId *)homeAccountId + environment:(NSString *)environment + tenantProfiles:(NSArray *)tenantProfiles; /*! Initialize an MSALAccount with MSIDAccount @param account MSID account + @param createTenantProfile Whether to create tenant profile based on the info of MSID account */ -- (id)initWithMSIDAccount:(MSIDAccount *)account; +- (instancetype)initWithMSIDAccount:(MSIDAccount *)account createTenantProfile:(BOOL)createTenantProfile; +- (instancetype)initWithMSALExternalAccount:(id)externalAccount + oauth2Provider:(MSALOauth2Provider *)oauthProvider; + +- (void)addTenantProfiles:(NSArray *)tenantProfiles; @end diff --git a/MSAL/src/MSALAccount.m b/MSAL/src/MSALAccount.m index e840e7ef03..b9ff7bd2cb 100644 --- a/MSAL/src/MSALAccount.m +++ b/MSAL/src/MSALAccount.m @@ -36,77 +36,109 @@ #import "MSIDAccount.h" #import "MSALAccountId+Internal.h" #import "MSIDAuthority.h" - -@interface MSALAccount () - -@property (nonatomic) MSALAccountId *homeAccountId; -@property (nonatomic) NSString *username; -@property (nonatomic) NSString *environment; - -@end +#import "MSALTenantProfile.h" +#import "MSALTenantProfile+Internal.h" +#import "MSALPublicClientApplication+Internal.h" +#import "MSALAccountsProvider.h" +#import "MSALAuthority_Internal.h" +#import "MSALOauth2Provider.h" +#import "MSIDAccountIdentifier.h" @implementation MSALAccount -- (id)initWithUsername:(NSString *)username - name:(NSString *)name - homeAccountId:(NSString *)homeAccountId - localAccountId:(NSString *)localAccountId - environment:(NSString *)environment - tenantId:(NSString *)tenantId +- (instancetype)initWithUsername:(NSString *)username + homeAccountId:(MSALAccountId *)homeAccountId + environment:(NSString *)environment + tenantProfiles:(NSArray *)tenantProfiles { self = [super init]; if (self) { _username = username; - _name = name; _environment = environment; - - NSArray *accountIdComponents = [homeAccountId componentsSeparatedByString:@"."]; - - NSString *uid = nil; - NSString *utid = nil; - - if ([accountIdComponents count] == 2) + _homeAccountId = homeAccountId; + _identifier = homeAccountId.identifier; + _lookupAccountIdentifier = [[MSIDAccountIdentifier alloc] initWithDisplayableId:username homeAccountId:homeAccountId.identifier]; + + if (tenantProfiles.count > 0) { - uid = accountIdComponents[0]; - utid = accountIdComponents[1]; + self.mTenantProfiles = [[NSMutableArray alloc] initWithArray:tenantProfiles]; } - - _homeAccountId = [[MSALAccountId alloc] initWithAccountIdentifier:homeAccountId - objectId:uid - tenantId:utid]; - - _localAccountId = [[MSALAccountId alloc] initWithAccountIdentifier:localAccountId - objectId:localAccountId - tenantId:tenantId]; - - _lookupAccountIdentifier = [[MSIDAccountIdentifier alloc] initWithDisplayableId:username homeAccountId:homeAccountId]; } return self; } -- (id)initWithMSIDAccount:(MSIDAccount *)account +- (instancetype)initWithMSIDAccount:(MSIDAccount *)account + createTenantProfile:(BOOL)createTenantProfile { + NSArray *tenantProfiles = nil; + if (createTenantProfile) + { + NSDictionary *allClaims = account.idTokenClaims.jsonDictionary; + + MSALTenantProfile *tenantProfile = [[MSALTenantProfile alloc] initWithIdentifier:account.localAccountId + tenantId:account.realm + environment:account.environment + isHomeTenantProfile:account.isHomeTenantAccount + claims:allClaims]; + if (tenantProfile) + { + tenantProfiles = @[tenantProfile]; + } + } + + MSALAccountId *homeAccountId = [[MSALAccountId alloc] initWithAccountIdentifier:account.accountIdentifier.homeAccountId + objectId:account.accountIdentifier.uid + tenantId:account.accountIdentifier.utid]; + return [self initWithUsername:account.username - name:account.name - homeAccountId:account.accountIdentifier.homeAccountId - localAccountId:account.localAccountId - environment:account.authority.environment - tenantId:account.authority.url.msidTenant]; + homeAccountId:homeAccountId + environment:account.environment + tenantProfiles:tenantProfiles]; +} + +- (instancetype)initWithMSALExternalAccount:(id)externalAccount + oauth2Provider:(MSALOauth2Provider *)oauthProvider +{ + MSIDAccountIdentifier *accountIdentifier = [[MSIDAccountIdentifier alloc] initWithDisplayableId:nil homeAccountId:externalAccount.identifier]; + MSALAccountId *homeAccountId = [[MSALAccountId alloc] initWithAccountIdentifier:accountIdentifier.homeAccountId + objectId:accountIdentifier.uid + tenantId:accountIdentifier.utid]; + + NSError *tenantProfileError = nil; + MSALTenantProfile *tenantProfile = [oauthProvider tenantProfileWithClaims:externalAccount.accountClaims + homeAccountId:homeAccountId + environment:externalAccount.environment + error:&tenantProfileError]; + + if (tenantProfileError) + { + MSID_LOG_WITH_CTX(MSIDLogLevelWarning, nil, @"Failed to create tenant profile with error code %ld, domain %@", (long)tenantProfileError.code, tenantProfileError.domain); + } + + NSArray *tenantProfiles = tenantProfile ? @[tenantProfile] : nil; + + MSALAccount *account = [self initWithUsername:externalAccount.username + homeAccountId:homeAccountId + environment:externalAccount.environment + tenantProfiles:tenantProfiles]; + + return account; } #pragma mark - NSCopying -- (id)copyWithZone:(NSZone *)zone +- (instancetype)copyWithZone:(NSZone *)zone { - MSALAccount *account = [[MSALAccount allocWithZone:zone] init]; - account.username = [self.username copyWithZone:zone]; - account.name = [self.name copyWithZone:zone]; - account.homeAccountId = [self.homeAccountId copyWithZone:zone]; - account.localAccountId = [self.localAccountId copyWithZone:zone]; - account.environment = [self.environment copyWithZone:zone]; + NSString *username = [self.username copyWithZone:zone]; + MSALAccountId *homeAccountId = [self.homeAccountId copyWithZone:zone]; + NSString *environment = [self.environment copyWithZone:zone]; + NSArray *tenantProfiles = [[NSMutableArray alloc] initWithArray:self.mTenantProfiles copyItems:YES]; + + MSALAccount *account = [[MSALAccount allocWithZone:zone] initWithUsername:username homeAccountId:homeAccountId environment:environment tenantProfiles:tenantProfiles]; + account.accountClaims = [self.accountClaims copyWithZone:zone]; return account; } @@ -124,64 +156,48 @@ - (BOOL)isEqual:(id)object return NO; } - return [self isEqualToUser:(MSALAccount *)object]; + return [self isEqualToAccount:(MSALAccount *)object]; } -/* - TODO: this is correct implementation, but we can't use it until we agree on the public API changes - (NSUInteger)hash { NSUInteger hash = 0; hash = hash * 31 + self.username.hash; - hash = hash * 31 + self.name.hash; hash = hash * 31 + self.homeAccountId.hash; - hash = hash * 31 + self.localAccountId.hash; hash = hash * 31 + self.environment.hash; - hash = hash * 31 + self.tenantId.hash; - hash = hash * 31 + self.uid.hash; - hash = hash * 31 + self.utid.hash; return hash; } -- (BOOL)isEqualToUser:(MSALAccount *)user +- (BOOL)isEqualToAccount:(MSALAccount *)user { if (!user) return NO; - + BOOL result = YES; result &= (!self.username && !user.username) || [self.username isEqualToString:user.username]; - result &= (!self.name && !user.name) || [self.name isEqualToString:user.name]; - result &= (!self.homeAccountId && !user.homeAccountId) || [self.homeAccountId isEqualToString:user.homeAccountId]; - result &= (!self.localAccountId && !user.localAccountId) || [self.localAccountId isEqualToString:user.localAccountId]; + result &= (!self.homeAccountId && !user.homeAccountId) || [self.homeAccountId.identifier isEqualToString:user.homeAccountId.identifier]; result &= (!self.environment && !user.environment) || [self.environment isEqualToString:user.environment]; - result &= (!self.tenantId && !user.tenantId) || [self.tenantId isEqualToString:user.tenantId]; - result &= (!self.uid && !user.uid) || [self.uid isEqualToString:user.uid]; - result &= (!self.utid && !user.utid) || [self.utid isEqualToString:user.utid]; - return result; -}*/ +} -/* TODO: this is a temporary solution that maintains previous MSAL behavior of having one account per environment. - This is a temporary solution to test the overall app and will be removed once we agree on the public API changes. */ +#pragma mark - Tenant profiles -- (NSUInteger)hash +- (NSArray *)tenantProfiles { - NSUInteger hash = 0; - hash = hash * 31 + self.username.hash; - hash = hash * 31 + self.homeAccountId.hash; - hash = hash * 31 + self.environment.hash; - return hash; + return self.mTenantProfiles; } -- (BOOL)isEqualToUser:(MSALAccount *)user +- (void)addTenantProfiles:(NSArray *)tenantProfiles { - if (!user) return NO; - - BOOL result = YES; - result &= (!self.username && !user.username) || [self.username isEqualToString:user.username]; - result &= (!self.homeAccountId && !user.homeAccountId) || [self.homeAccountId.identifier isEqualToString:user.homeAccountId.identifier]; - result &= (!self.environment && !user.environment) || [self.environment isEqualToString:user.environment]; - - return result; + if (tenantProfiles.count <= 0) return; + + if (self.mTenantProfiles) + { + [self.mTenantProfiles addObjectsFromArray:tenantProfiles]; + } + else + { + self.mTenantProfiles = [[NSMutableArray alloc] initWithArray:tenantProfiles]; + } } @end diff --git a/MSAL/src/MSALAccountEnumerationParameters.m b/MSAL/src/MSALAccountEnumerationParameters.m new file mode 100644 index 0000000000..c3dd822cf7 --- /dev/null +++ b/MSAL/src/MSALAccountEnumerationParameters.m @@ -0,0 +1,100 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALAccountEnumerationParameters.h" + +@interface MSALAccountEnumerationParameters() + +@property (nonatomic, readwrite, nullable) NSString *identifier; +@property (nonatomic, readwrite, nullable) NSString *tenantProfileIdentifier; +@property (nonatomic, readwrite, nullable) NSString *username; + +@end + +@implementation MSALAccountEnumerationParameters + +- (instancetype)init +{ + self = [super init]; + + if (self) + { + _returnOnlySignedInAccounts = YES; + } + + return self; +} + +- (instancetype)initWithIdentifier:(nonnull NSString *)accountIdentifier +{ + self = [super init]; + + if (self) + { + _identifier = accountIdentifier; + _returnOnlySignedInAccounts = YES; + } + + return self; +} + +- (instancetype)initWithIdentifier:(nullable NSString *)accountIdentifier + username:(nonnull NSString *)username +{ + self = [super init]; + + if (self) + { + _identifier = accountIdentifier; + _username = username; + _returnOnlySignedInAccounts = YES; + } + + return self; +} + +- (instancetype)initWithTenantProfileIdentifier:(nonnull NSString *)tenantProfileIdentifier +{ + self = [super init]; + + if (self) + { + _tenantProfileIdentifier = tenantProfileIdentifier; + _returnOnlySignedInAccounts = YES; + } + + return self; +} + +#pragma mark - Description + +- (NSString *)description +{ + return [NSString stringWithFormat:@"Account identifier %@, username %@, tenant profile identifier %@, return only signed in accounts %d", self.identifier, self.username, self.tenantProfileIdentifier, self.returnOnlySignedInAccounts]; +} + +@end diff --git a/MSAL/src/MSALAccountId.m b/MSAL/src/MSALAccountId.m index 56f9b547b8..fd613ef248 100644 --- a/MSAL/src/MSALAccountId.m +++ b/MSAL/src/MSALAccountId.m @@ -54,8 +54,6 @@ - (NSUInteger)hash { NSUInteger hash = 0; hash = hash * 31 + self.identifier.hash; - hash = hash * 31 + self.objectId.hash; - hash = hash * 31 + self.tenantId.hash; return hash; } @@ -78,8 +76,16 @@ - (BOOL)isEqualToItem:(MSALAccountId *)accountId { BOOL result = YES; result &= (!self.identifier && !accountId.identifier) || [self.identifier isEqualToString:accountId.identifier]; - result &= (!self.objectId && !accountId.objectId) || [self.objectId isEqualToString:accountId.objectId]; - result &= (!self.tenantId && !accountId.tenantId) || [self.tenantId isEqualToString:accountId.tenantId]; + + if (self.objectId && accountId.objectId) + { + result &= [self.objectId isEqualToString:accountId.objectId]; + } + + if (self.tenantId && accountId.tenantId) + { + result &= [self.tenantId isEqualToString:accountId.tenantId]; + } return result; } diff --git a/MSAL/src/MSALClaimsRequest.m b/MSAL/src/MSALClaimsRequest.m index e98b302d47..6448b67cd5 100644 --- a/MSAL/src/MSALClaimsRequest.m +++ b/MSAL/src/MSALClaimsRequest.m @@ -119,8 +119,7 @@ - (NSString *)jsonString if (msidError) { - MSID_LOG_ERROR(nil, @"Failed to serialize claims request to json string. Error %ld, %@", (long)msidError.code, msidError.domain); - MSID_LOG_ERROR_PII(nil, @"Failed to serialize claims request to json string. Error %@", msidError); + MSID_LOG_WITH_CTX_PII(MSIDLogLevelError, nil, @"Failed to serialize claims request to json string. Error %@", MSID_PII_LOG_MASKABLE(msidError)); } return result; @@ -130,7 +129,9 @@ - (NSString *)jsonString - (void)commonInit { - _jsonSerializer = [MSIDJsonSerializer new]; + MSIDJsonSerializer *jsonSerializer = [MSIDJsonSerializer new]; + jsonSerializer.normalizeJSON = NO; + _jsonSerializer = jsonSerializer; } - (MSIDClaimsRequestTarget)msidTargetFromTarget:(MSALClaimsRequestTarget)target diff --git a/MSAL/src/MSALErrorConverter+Internal.h b/MSAL/src/MSALErrorConverter+Internal.h index 344d09aea1..156f6c8990 100644 --- a/MSAL/src/MSALErrorConverter+Internal.h +++ b/MSAL/src/MSALErrorConverter+Internal.h @@ -27,6 +27,8 @@ #import "MSALErrorConverter.h" +@class MSALOauth2Provider; + @interface MSALErrorConverter (Internal) + (NSError *)errorWithDomain:(NSString *)domain @@ -36,6 +38,8 @@ subError:(NSString *)subError underlyingError:(NSError *)underlyingError correlationId:(NSUUID *)correlationId - userInfo:(NSDictionary *)userInfo; + userInfo:(NSDictionary *)userInfo + classifyErrors:(BOOL)shouldClassifyErrors + msalOauth2Provider:(MSALOauth2Provider *)oauth2Provider; @end diff --git a/MSAL/src/MSALErrorConverter.h b/MSAL/src/MSALErrorConverter.h index 5a5b860f77..45eded24fe 100644 --- a/MSAL/src/MSALErrorConverter.h +++ b/MSAL/src/MSALErrorConverter.h @@ -27,8 +27,11 @@ #import "MSIDError.h" +@class MSALOauth2Provider; + @interface MSALErrorConverter : NSObject + (NSError *)msalErrorFromMsidError:(NSError *)msidError; ++ (NSError *)msalErrorFromMsidError:(NSError *)msidError classifyErrors:(BOOL)shouldClassifyErrors msalOauth2Provider:(MSALOauth2Provider *)oauth2Provider; @end diff --git a/MSAL/src/MSALErrorConverter.m b/MSAL/src/MSALErrorConverter.m index d7dc799cb9..bdc9e0973c 100644 --- a/MSAL/src/MSALErrorConverter.m +++ b/MSAL/src/MSALErrorConverter.m @@ -28,6 +28,7 @@ #import "MSALErrorConverter+Internal.h" #import "MSALResult+Internal.h" #import "MSALError.h" +#import "MSALOauth2Provider.h" static NSDictionary *s_errorDomainMapping; static NSDictionary *s_errorCodeMapping; @@ -123,6 +124,13 @@ + (void)initialize } + (NSError *)msalErrorFromMsidError:(NSError *)msidError +{ + return [self msalErrorFromMsidError:msidError classifyErrors:YES msalOauth2Provider:nil]; +} + ++ (NSError *)msalErrorFromMsidError:(NSError *)msidError + classifyErrors:(BOOL)shouldClassifyErrors + msalOauth2Provider:(MSALOauth2Provider *)oauth2Provider { return [self errorWithDomain:msidError.domain code:msidError.code @@ -131,7 +139,9 @@ + (NSError *)msalErrorFromMsidError:(NSError *)msidError subError:msidError.userInfo[MSIDOAuthSubErrorKey] underlyingError:msidError.userInfo[NSUnderlyingErrorKey] correlationId:msidError.userInfo[MSIDCorrelationIdKey] - userInfo:msidError.userInfo]; + userInfo:msidError.userInfo + classifyErrors:shouldClassifyErrors + msalOauth2Provider:oauth2Provider]; } + (NSError *)errorWithDomain:(NSString *)domain @@ -142,6 +152,8 @@ + (NSError *)errorWithDomain:(NSString *)domain underlyingError:(NSError *)underlyingError correlationId:(NSUUID *)correlationId userInfo:(NSDictionary *)userInfo + classifyErrors:(BOOL)shouldClassifyErrors + msalOauth2Provider:(MSALOauth2Provider *)oauth2Provider { if ([NSString msidIsStringNilOrBlank:domain]) { @@ -155,21 +167,27 @@ + (NSError *)errorWithDomain:(NSString *)domain // errorCode mapping is needed only if domain is mapped to MSALErrorDomain NSNumber *mappedCode = nil; NSNumber *internalCode = nil; - if (mappedDomain == MSALErrorDomain) + if ([mappedDomain isEqualToString:MSALErrorDomain]) { mappedCode = s_errorCodeMapping[mappedDomain][@(code)]; if (mappedCode == nil) { - MSID_LOG_WARN(nil, @"MSALErrorConverter could not find the error code mapping entry for domain (%@) + error code (%ld).", domain, (long)code); - mappedCode = @(MSALErrorInternal); - } - - if (![s_recoverableErrorCode containsObject:mappedCode]) - { - internalCode = mappedCode; + MSID_LOG_WITH_CTX(MSIDLogLevelWarning,nil, @"MSALErrorConverter could not find the error code mapping entry for domain (%@) + error code (%ld).", domain, (long)code); mappedCode = @(MSALErrorInternal); } } + else if ([domain isEqualToString:MSALErrorDomain]) + { + mappedCode = @(code); + } + + if (shouldClassifyErrors && mappedCode != nil && ![s_recoverableErrorCode containsObject:mappedCode]) + { + // If mapped code is MSALErrorInternal, set internalCode to MSALInternalErrorUnexpected + // to avoid the case when both mapped and internal code are MSALErrorInternal. + internalCode = [mappedCode isEqual:@(MSALErrorInternal)] ? @(MSALInternalErrorUnexpected) : mappedCode; + mappedCode = @(MSALErrorInternal); + } NSMutableDictionary *msalUserInfo = [NSMutableDictionary new]; @@ -185,15 +203,14 @@ + (NSError *)errorWithDomain:(NSString *)domain msalUserInfo[NSUnderlyingErrorKey] = underlyingError; msalUserInfo[MSALInternalErrorCodeKey] = internalCode; - if (userInfo[MSIDInvalidTokenResultKey]) + if (userInfo[MSIDInvalidTokenResultKey] && oauth2Provider) { NSError *resultError = nil; - MSALResult *msalResult = [MSALResult resultWithTokenResult:userInfo[MSIDInvalidTokenResultKey] error:&resultError]; + MSALResult *msalResult = [oauth2Provider resultWithTokenResult:userInfo[MSIDInvalidTokenResultKey] error:&resultError]; if (!msalResult) { - MSID_LOG_NO_PII(MSIDLogLevelWarning, nil, nil, @"MSALErrorConverter could not convert MSIDTokenResult to MSALResult %ld, %@", (long)resultError.code, resultError.domain); - MSID_LOG_PII(MSIDLogLevelWarning, nil, nil, @"MSALErrorConverter could not convert MSIDTokenResult to MSALResult %@", resultError); + MSID_LOG_WITH_CTX_PII(MSIDLogLevelWarning, nil, @"MSALErrorConverter could not convert MSIDTokenResult to MSALResult %@", MSID_PII_LOG_MASKABLE(resultError)); } else { diff --git a/MSAL/src/MSALIndividualClaimRequestAdditionalInfo.m b/MSAL/src/MSALIndividualClaimRequestAdditionalInfo.m index ce713f1ee6..171c126b98 100644 --- a/MSAL/src/MSALIndividualClaimRequestAdditionalInfo.m +++ b/MSAL/src/MSALIndividualClaimRequestAdditionalInfo.m @@ -37,7 +37,9 @@ - (instancetype)init if (self) { _msidAdditionalInfo = [MSIDIndividualClaimRequestAdditionalInfo new]; - _jsonSerializer = [MSIDJsonSerializer new]; + MSIDJsonSerializer *jsonSerializer = [MSIDJsonSerializer new]; + jsonSerializer.normalizeJSON = NO; + _jsonSerializer = jsonSerializer; } return self; } diff --git a/MSAL/src/MSALInteractiveTokenParameters.m b/MSAL/src/MSALInteractiveTokenParameters.m index f5b94ebfd2..6e585f1f7d 100644 --- a/MSAL/src/MSALInteractiveTokenParameters.m +++ b/MSAL/src/MSALInteractiveTokenParameters.m @@ -31,12 +31,16 @@ @implementation MSALInteractiveTokenParameters +@synthesize telemetryApiId; + - (instancetype)initWithScopes:(NSArray *)scopes { self = [super initWithScopes:scopes]; if (self) { - _webviewType = MSALGlobalConfig.defaultWebviewType; + self.webviewType = MSALGlobalConfig.defaultWebviewType; + self.promptType = MSALPromptTypeDefault; + self.telemetryApiId = MSALTelemetryApiIdAcquireWithTokenParameters; } return self; } diff --git a/MSAL/src/MSALPublicClientApplication+Internal.h b/MSAL/src/MSALPublicClientApplication+Internal.h index e96c25f4f3..6b03bfdcfa 100644 --- a/MSAL/src/MSALPublicClientApplication+Internal.h +++ b/MSAL/src/MSALPublicClientApplication+Internal.h @@ -28,13 +28,19 @@ #import "MSALPublicClientApplication.h" @class MSIDDefaultTokenCacheAccessor; +@class MSIDAccountMetadataCacheAccessor; @class MSIDAuthority; +@class MSALOauth2Provider; +@class MSALExternalAccountHandler; -@interface MSALPublicClientApplication (Internal) +@interface MSALPublicClientApplication () @property (nonatomic, nonnull) MSIDDefaultTokenCacheAccessor *tokenCache; +@property (nonatomic, nonnull) MSIDAccountMetadataCacheAccessor *accountMetadataCache; +@property (nonatomic, nonnull) MSALOauth2Provider *msalOauth2Provider; +@property (nonatomic, nullable) MSALExternalAccountHandler *externalAccountHandler; + (nonnull NSOrderedSet *)defaultOIDCScopes; -- (BOOL)shouldDisableValidationForAuthority:(nonnull MSIDAuthority *)authority; +- (BOOL)shouldExcludeValidationForAuthority:(nonnull MSIDAuthority *)authority; @end diff --git a/MSAL/src/MSALPublicClientApplication.m b/MSAL/src/MSALPublicClientApplication.m index 49a9771c24..23b910cc22 100644 --- a/MSAL/src/MSALPublicClientApplication.m +++ b/MSAL/src/MSALPublicClientApplication.m @@ -31,10 +31,6 @@ #import "MSALTelemetryApiId.h" #import "MSALTelemetry.h" -#if TARGET_OS_IPHONE -#import "MSIDKeychainTokenCache.h" -#import "MSIDCertAuthHandler+iOS.h" -#endif #import "MSIDMacTokenCache.h" #import "MSIDLegacyTokenCacheAccessor.h" #import "MSIDDefaultTokenCacheAccessor.h" @@ -44,7 +40,7 @@ #import "MSALAADAuthority.h" #import "MSALAuthority_Internal.h" #import "MSIDAADV2Oauth2Factory.h" -#import "MSALOauth2FactoryProducer.h" +#import "MSALOauth2ProviderFactory.h" #import "MSALWebviewType_Internal.h" #import "MSIDAuthority.h" #import "MSIDAADV2Oauth2Factory.h" @@ -59,11 +55,7 @@ #import "MSIDDefaultTokenRequestProvider.h" #import "MSIDAADNetworkConfiguration.h" #import "MSALAccountId.h" -#import "MSIDAuthorityFactory.h" #import "MSALErrorConverter.h" -#if TARGET_OS_IPHONE -#import "MSIDBrokerInteractiveController.h" -#endif #import "MSIDDefaultBrokerResponseHandler.h" #import "MSIDDefaultTokenResponseValidator.h" #import "MSALRedirectUri.h" @@ -74,6 +66,7 @@ #import "MSIDIntuneEnrollmentIdsCache.h" #import "MSALPublicClientStatusNotifications.h" #import "MSIDNotifications.h" +#import "MSALTokenParameters+Internal.h" #import "MSALInteractiveTokenParameters.h" #import "MSALSilentTokenParameters.h" #import "MSALSliceConfig.h" @@ -85,6 +78,23 @@ #import "MSIDAADAuthority.h" #import "MSALCacheConfig.h" #import "MSALClaimsRequest+Internal.h" +#import "MSALExternalAccountHandler.h" +#import "MSALSerializedADALCacheProvider+Internal.h" +#import "MSIDExternalAADCacheSeeder.h" +#import "NSURL+MSIDAADUtils.h" +#import "MSALOauth2Provider.h" +#import "MSALAccountEnumerationParameters.h" +#import "MSIDAccountMetadataCacheAccessor.h" +#import "MSIDExtendedTokenCacheDataSource.h" + +#if TARGET_OS_IPHONE +#import "MSIDKeychainTokenCache.h" +#import "MSIDCertAuthHandler+iOS.h" +#import "MSIDBrokerInteractiveController.h" +#else +#import "MSIDMacKeychainTokenCache.h" +#endif + @interface MSALPublicClientApplication() { @@ -92,8 +102,8 @@ @interface MSALPublicClientApplication() NSString *_defaultKeychainGroup; } -@property (nonatomic) MSIDDefaultTokenCacheAccessor *tokenCache; @property (nonatomic) MSALPublicClientApplicationConfig *internalConfig; +@property (nonatomic) MSIDExternalAADCacheSeeder *externalCacheSeeder; @end @@ -122,8 +132,8 @@ - (MSALRedirectUri *)redirectUri { return self.internalConfig.verifiedRedirectUr - (NSDictionary *)sliceParameters { return self.internalConfig.sliceConfig.sliceDictionary; } - (void)setSliceParameters:(NSDictionary *)sliceParameters { - if (!sliceParameters) MSID_LOG_WARN(nil, @"setting slice parameter with nil object."); - if (!sliceParameters[@"slice"] && !sliceParameters[@"dc"]) MSID_LOG_WARN(nil, @"slice parameter does not contain slice nor dc"); + if (!sliceParameters) MSID_LOG_WITH_CTX(MSIDLogLevelWarning,nil, @"setting slice parameter with nil object."); + if (!sliceParameters[@"slice"] && !sliceParameters[@"dc"]) MSID_LOG_WITH_CTX(MSIDLogLevelWarning,nil, @"slice parameter does not contain slice nor dc"); self.internalConfig.sliceConfig = [MSALSliceConfig configWithSlice:sliceParameters[@"slice"] dc:sliceParameters[@"dc"]]; } @@ -216,7 +226,7 @@ - (nullable instancetype)initWithConfiguration:(nonnull MSALPublicClientApplicat return nil; } - + NSError *msidError = nil; MSALRedirectUri *msalRedirectUri = [MSALRedirectUriVerifier msalRedirectUriWithCustomUri:config.redirectUri clientId:config.clientId @@ -235,25 +245,79 @@ - (nullable instancetype)initWithConfiguration:(nonnull MSALPublicClientApplicat MSIDKeychainTokenCache *dataSource = [[MSIDKeychainTokenCache alloc] initWithGroup:config.cacheConfig.keychainSharingGroup]; MSIDLegacyTokenCacheAccessor *legacyAccessor = [[MSIDLegacyTokenCacheAccessor alloc] initWithDataSource:dataSource otherCacheAccessors:nil]; - MSIDDefaultTokenCacheAccessor *defaultAccessor = [[MSIDDefaultTokenCacheAccessor alloc] initWithDataSource:dataSource otherCacheAccessors:@[legacyAccessor]]; - + NSArray *otherAccessors = legacyAccessor ? @[legacyAccessor] : nil; + MSIDDefaultTokenCacheAccessor *defaultAccessor = [[MSIDDefaultTokenCacheAccessor alloc] initWithDataSource:dataSource otherCacheAccessors:otherAccessors]; self.tokenCache = defaultAccessor; #else - __auto_type dataSource = MSIDMacTokenCache.defaultCache; + id dataSource = [[MSIDMacKeychainTokenCache alloc] initWithGroup:config.cacheConfig.keychainSharingGroup]; + + if (!dataSource) + { + MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"Failed to initialize macOS keychain cache. Please make sure the app you're running is properly signed"); + + if (error) + { + NSError *devError = MSIDCreateError(MSIDErrorDomain, MSIDErrorInvalidDeveloperParameter, @"Failed to initialize macOS keychain cache. Please make sure the app you're running is properly signed", nil, nil, nil, nil, nil); + *error = [MSALErrorConverter msalErrorFromMsidError:devError]; + } + + return nil; + } + + NSMutableArray *legacyAccessors = [NSMutableArray new]; + id externalDataSource = config.cacheConfig.serializedADALCache.msidTokenCacheDataSource; + if (externalDataSource) + { + __auto_type legacyAccessor = [[MSIDLegacyTokenCacheAccessor alloc] initWithDataSource:externalDataSource otherCacheAccessors:nil]; + __auto_type defaultAccessor = [[MSIDDefaultTokenCacheAccessor alloc] initWithDataSource:dataSource otherCacheAccessors:nil]; + _externalCacheSeeder = [[MSIDExternalAADCacheSeeder alloc] initWithDefaultAccessor:defaultAccessor + externalLegacyAccessor:legacyAccessor]; + if (legacyAccessor) [legacyAccessors addObject:legacyAccessor]; + } - MSIDDefaultTokenCacheAccessor *defaultAccessor = [[MSIDDefaultTokenCacheAccessor alloc] initWithDataSource:dataSource otherCacheAccessors:nil]; + MSIDDefaultTokenCacheAccessor *defaultAccessor = [[MSIDDefaultTokenCacheAccessor alloc] initWithDataSource:dataSource otherCacheAccessors:legacyAccessors]; self.tokenCache = defaultAccessor; #endif + + _accountMetadataCache = [[MSIDAccountMetadataCacheAccessor alloc] initWithDataSource:dataSource]; + // Maintain an internal copy of config. // Developers shouldn't be able to change any properties on config after PCA has been created _configuration = config; _internalConfig = [config copy]; MSIDAADNetworkConfiguration.defaultConfiguration.aadApiVersion = @"v2.0"; + NSError *oauthProviderError = nil; + self.msalOauth2Provider = [MSALOauth2ProviderFactory oauthProviderForAuthority:config.authority + clientId:config.clientId + tokenCache:_tokenCache + accountMetadataCache:_accountMetadataCache + context:nil + error:&oauthProviderError]; + + if (!self.msalOauth2Provider) + { + if (error) + { + *error = oauthProviderError; + } + + return nil; + } + + if ([_internalConfig.cacheConfig.externalAccountProviders count]) + { + _externalAccountHandler = [[MSALExternalAccountHandler alloc] initWithExternalAccountProviders:_internalConfig.cacheConfig.externalAccountProviders + oauth2Provider:self.msalOauth2Provider + error:error]; + + if (!_externalAccountHandler) return nil; + } return self; } + - (id)initWithClientId:(NSString *)clientId keychainGroup:(NSString *)keychainGroup authority:(MSALAuthority *)authority @@ -267,7 +331,7 @@ - (id)initWithClientId:(NSString *)clientId MSALPublicClientApplicationConfig *config = [[MSALPublicClientApplicationConfig alloc] initWithClientId:clientId redirectUri:redirectUri authority:authority]; #if TARGET_OS_IPHONE - config.cacheConfig.keychainSharingGroup = keychainGroup ?: [[NSBundle mainBundle] bundleIdentifier]; + config.cacheConfig.keychainSharingGroup = keychainGroup; #endif return [self initWithConfiguration:config error:error]; @@ -278,7 +342,8 @@ - (id)initWithClientId:(NSString *)clientId - (NSArray *)allAccounts:(NSError * __autoreleasing *)error { MSALAccountsProvider *request = [[MSALAccountsProvider alloc] initWithTokenCache:self.tokenCache - clientId:self.internalConfig.clientId]; + clientId:self.internalConfig.clientId + externalAccountProvider:self.externalAccountHandler]; NSError *msidError = nil; NSArray *accounts = [request allAccounts:&msidError]; if (error) *error = [MSALErrorConverter msalErrorFromMsidError:msidError]; @@ -288,35 +353,61 @@ - (id)initWithClientId:(NSString *)clientId - (MSALAccount *)accountForHomeAccountId:(NSString *)homeAccountId error:(NSError * __autoreleasing *)error +{ + return [self accountForIdentifier:homeAccountId error:error]; +} + +- (MSALAccount *)accountForIdentifier:(NSString *)identifier + error:(NSError **)error { MSALAccountsProvider *request = [[MSALAccountsProvider alloc] initWithTokenCache:self.tokenCache - clientId:self.internalConfig.clientId]; + clientId:self.internalConfig.clientId + externalAccountProvider:self.externalAccountHandler]; NSError *msidError = nil; - MSALAccount *account = [request accountForHomeAccountId:homeAccountId error:&msidError]; - + + MSALAccountEnumerationParameters *parameters = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:identifier]; + + MSALAccount *account = [request accountForParameters:parameters error:&msidError]; + if (error) *error = [MSALErrorConverter msalErrorFromMsidError:msidError]; - + return account; } +- (NSArray *)accountsForParameters:(MSALAccountEnumerationParameters *)parameters + error:(NSError **)error +{ + MSALAccountsProvider *request = [[MSALAccountsProvider alloc] initWithTokenCache:self.tokenCache + clientId:self.internalConfig.clientId + externalAccountProvider:self.externalAccountHandler]; + NSError *msidError = nil; + NSArray *accounts = [request accountsForParameters:parameters error:&msidError]; + + if (error) *error = [MSALErrorConverter msalErrorFromMsidError:msidError]; + + return accounts; +} + - (MSALAccount *)accountForUsername:(NSString *)username error:(NSError * __autoreleasing *)error { MSALAccountsProvider *request = [[MSALAccountsProvider alloc] initWithTokenCache:self.tokenCache - clientId:self.internalConfig.clientId]; + clientId:self.internalConfig.clientId + externalAccountProvider:self.externalAccountHandler]; NSError *msidError = nil; - MSALAccount *account = [request accountForUsername:username error:&msidError]; + MSALAccountEnumerationParameters *parameters = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:nil username:username]; + MSALAccount *account = [request accountForParameters:parameters error:&msidError]; if (error) *error = [MSALErrorConverter msalErrorFromMsidError:msidError]; return account; } - - (void)allAccountsFilteredByAuthority:(MSALAccountsCompletionBlock)completionBlock { MSALAccountsProvider *request = [[MSALAccountsProvider alloc] initWithTokenCache:self.tokenCache - clientId:self.internalConfig.clientId]; + clientId:self.internalConfig.clientId + externalAccountProvider:self.externalAccountHandler]; [request allAccountsFilteredByAuthority:self.internalConfig.authority completionBlock:^(NSArray *accounts, NSError *msidError) { @@ -347,7 +438,7 @@ + (BOOL)handleMSALResponse:(NSURL *)response if ([NSString msidIsStringNilOrBlank:sourceApplication]) { - MSID_LOG_WARN(nil, @"Application doesn't integrate with broker correctly"); + MSID_LOG_WITH_CTX(MSIDLogLevelWarning,nil, @"Application doesn't integrate with broker correctly"); // TODO: add a link to Wiki describing why broker is necessary return NO; } @@ -384,37 +475,180 @@ + (BOOL)cancelCurrentWebAuthSession - (void)acquireTokenWithParameters:(MSALInteractiveTokenParameters *)parameters completionBlock:(MSALCompletionBlock)completionBlock { - [self acquireTokenForScopes:parameters.scopes - extraScopesToConsent:parameters.extraScopesToConsent - account:parameters.account - loginHint:parameters.loginHint - promptType:parameters.promptType - extraQueryParameters:parameters.extraQueryParameters - claimsRequest:parameters.claimsRequest - authority:parameters.authority - webviewType:parameters.webviewType - customWebview:parameters.customWebview - correlationId:parameters.correlationId - apiId:MSALTelemetryApiIdAcquireWithTokenParameters - completionBlock:completionBlock]; + MSIDAuthority *requestAuthority = parameters.authority.msidAuthority ?: self.internalConfig.authority.msidAuthority; + + if (![self.msalOauth2Provider isSupportedAuthority:requestAuthority]) + { + if (completionBlock) + { + NSError *msidError = MSIDCreateError(MSIDErrorDomain, MSIDErrorInvalidDeveloperParameter, @"Unsupported authority type. Please configure MSALPublicClientApplication with the same authority type", nil, nil, nil, nil, nil); + NSError *msalError = [MSALErrorConverter msalErrorFromMsidError:msidError]; + completionBlock(nil, msalError); + } + + return; + } + + NSError *msidError = nil; + + MSIDInteractiveRequestType interactiveRequestType = MSIDInteractiveRequestBrokeredType; + +#if TARGET_OS_IPHONE + if (MSALGlobalConfig.brokerAvailability == MSALBrokeredAvailabilityNone) + { + interactiveRequestType = MSIDInteractiveRequestLocalType; + } + else if (!self.internalConfig.verifiedRedirectUri.brokerCapable) + { + interactiveRequestType = MSIDInteractiveRequestLocalType; + } +#endif + MSIDInteractiveRequestParameters *msidParams = + [[MSIDInteractiveRequestParameters alloc] initWithAuthority:requestAuthority + redirectUri:self.internalConfig.verifiedRedirectUri.url.absoluteString + clientId:self.internalConfig.clientId + scopes:[[NSOrderedSet alloc] initWithArray:parameters.scopes copyItems:YES] + oidcScopes:[self.class defaultOIDCScopes] + extraScopesToConsent:parameters.extraScopesToConsent ? [[NSOrderedSet alloc] initWithArray:parameters.extraScopesToConsent copyItems:YES] : nil + correlationId:parameters.correlationId + telemetryApiId:[NSString stringWithFormat:@"%ld", (long)parameters.telemetryApiId] + supportedBrokerProtocol:MSID_BROKER_MSAL_SCHEME + requestType:interactiveRequestType + error:&msidError]; + + if (!msidParams) + { + completionBlock(nil, [MSALErrorConverter msalErrorFromMsidError:msidError]); + return; + } + + msidParams.promptType = MSIDPromptTypeForPromptType(parameters.promptType); + msidParams.loginHint = parameters.loginHint; + msidParams.extraAuthorizeURLQueryParameters = parameters.extraQueryParameters; + msidParams.accountIdentifier = parameters.account.lookupAccountIdentifier; + + msidParams.extraURLQueryParameters = self.internalConfig.extraQueryParameters.extraURLQueryParameters; + + NSMutableDictionary *extraAuthorizeURLQueryParameters = [self.internalConfig.extraQueryParameters.extraAuthorizeURLQueryParameters mutableCopy]; + [extraAuthorizeURLQueryParameters addEntriesFromDictionary:parameters.extraQueryParameters]; + msidParams.extraAuthorizeURLQueryParameters = extraAuthorizeURLQueryParameters; + msidParams.extraTokenRequestParameters = self.internalConfig.extraQueryParameters.extraTokenURLParameters; + + msidParams.tokenExpirationBuffer = self.internalConfig.tokenExpirationBuffer; + msidParams.extendedLifetimeEnabled = self.internalConfig.extendedLifetimeEnabled; + msidParams.clientCapabilities = self.internalConfig.clientApplicationCapabilities; + + msidParams.validateAuthority = _validateAuthority; + + if (msidParams.validateAuthority + && [self shouldExcludeValidationForAuthority:requestAuthority]) + { + msidParams.validateAuthority = NO; + } + +#if TARGET_OS_IPHONE + msidParams.parentViewController = parameters.parentViewController; + msidParams.presentationType = parameters.presentationStyle; +#endif + + // Configure webview + NSError *msidWebviewError = nil; + MSIDWebviewType msidWebViewType = MSIDWebviewTypeFromMSALType(parameters.webviewType, &msidWebviewError); + + if (msidWebviewError) + { + completionBlock(nil, [MSALErrorConverter msalErrorFromMsidError:msidWebviewError]); + return; + } + + msidParams.webviewType = msidWebViewType; + msidParams.telemetryWebviewType = MSALStringForMSALWebviewType(parameters.webviewType); + msidParams.customWebview = parameters.customWebview ?: self.customWebview; + msidParams.claimsRequest = parameters.claimsRequest.msidClaimsRequest; + + MSID_LOG_WITH_CTX_PII(MSIDLogLevelInfo, msidParams, + @"-[MSALPublicClientApplication acquireTokenWithParameters:%@\n" + " extraScopesToConsent:%@\n" + " account:%@\n" + " loginHint:%@\n" + " promptType:%@\n" + " extraQueryParameters:%@\n" + " authority:%@\n" + " webviewType:%@\n" + " customWebview:%@\n" + " correlationId:%@\n" + " capabilities:%@\n" + " claimsRequest:%@]", + parameters.scopes, + parameters.extraScopesToConsent, + MSID_PII_LOG_MASKABLE(parameters.account.homeAccountId), + MSID_PII_LOG_EMAIL(parameters.loginHint), + MSALStringForPromptType(parameters.promptType), + parameters.extraQueryParameters, + parameters.authority, + MSALStringForMSALWebviewType(parameters.webviewType), + parameters.customWebview ? @"Yes" : @"No", + parameters.correlationId, + self.internalConfig.clientApplicationCapabilities, + parameters.claimsRequest); + + MSALCompletionBlock block = ^(MSALResult *result, NSError *msidError) + { + NSError *msalError = [MSALErrorConverter msalErrorFromMsidError:msidError classifyErrors:YES msalOauth2Provider:self.msalOauth2Provider]; + [MSALPublicClientApplication logOperation:@"acquireToken" result:result error:msalError context:msidParams]; + + if ([NSThread isMainThread]) + { + completionBlock(result, msalError); + } + else + { + dispatch_async(dispatch_get_main_queue(), ^{ + completionBlock(result, msalError); + }); + } + }; + + MSIDDefaultTokenRequestProvider *tokenRequestProvider = [[MSIDDefaultTokenRequestProvider alloc] initWithOauthFactory:self.msalOauth2Provider.msidOauth2Factory + defaultAccessor:self.tokenCache + accountMetadataAccessor:self.accountMetadataCache + tokenResponseValidator:[MSIDDefaultTokenResponseValidator new]]; +#if TARGET_OS_OSX + tokenRequestProvider.externalCacheSeeder = self.externalCacheSeeder; +#endif + + NSError *requestError = nil; + id controller = [MSIDRequestControllerFactory interactiveControllerForParameters:msidParams tokenRequestProvider:tokenRequestProvider error:&requestError]; + + if (!controller) + { + block(nil, requestError); + return; + } + + [controller acquireToken:^(MSIDTokenResult * _Nullable result, NSError * _Nullable error) { + + if (error) + { + block(nil, error); + return; + } + + NSError *resultError = nil; + MSALResult *msalResult = [self.msalOauth2Provider resultWithTokenResult:result error:&resultError]; + [self updateExternalAccountsWithResult:msalResult context:msidParams]; + + block(msalResult, resultError); + }]; } - (void)acquireTokenForScopes:(NSArray *)scopes completionBlock:(MSALCompletionBlock)completionBlock { - [self acquireTokenForScopes:scopes - extraScopesToConsent:nil - account:nil - loginHint:nil - promptType:MSALPromptTypeDefault - extraQueryParameters:nil - claimsRequest:nil - authority:nil - webviewType:MSALGlobalConfig.defaultWebviewType - customWebview:nil - correlationId:nil - apiId:MSALTelemetryApiIdAcquire - completionBlock:completionBlock]; + __auto_type parameters = [[MSALInteractiveTokenParameters alloc] initWithScopes:scopes]; + parameters.telemetryApiId = MSALTelemetryApiIdAcquire; + + [self acquireTokenWithParameters:parameters completionBlock:completionBlock]; } #pragma mark - Login Hint @@ -423,19 +657,11 @@ - (void)acquireTokenForScopes:(NSArray *)scopes loginHint:(NSString *)loginHint completionBlock:(MSALCompletionBlock)completionBlock { - [self acquireTokenForScopes:scopes - extraScopesToConsent:nil - account:nil - loginHint:loginHint - promptType:MSALPromptTypeDefault - extraQueryParameters:nil - claimsRequest:nil - authority:nil - webviewType:MSALGlobalConfig.defaultWebviewType - customWebview:nil - correlationId:nil - apiId:MSALTelemetryApiIdAcquireWithHint - completionBlock:completionBlock]; + __auto_type parameters = [[MSALInteractiveTokenParameters alloc] initWithScopes:scopes]; + parameters.loginHint = loginHint; + parameters.telemetryApiId = MSALTelemetryApiIdAcquireWithHint; + + [self acquireTokenWithParameters:parameters completionBlock:completionBlock]; } - (void)acquireTokenForScopes:(NSArray *)scopes @@ -444,19 +670,13 @@ - (void)acquireTokenForScopes:(NSArray *)scopes extraQueryParameters:(NSDictionary *)extraQueryParameters completionBlock:(MSALCompletionBlock)completionBlock { - [self acquireTokenForScopes:scopes - extraScopesToConsent:nil - account:nil - loginHint:loginHint - promptType:promptType - extraQueryParameters:extraQueryParameters - claimsRequest:nil - authority:nil - webviewType:MSALGlobalConfig.defaultWebviewType - customWebview:nil - correlationId:nil - apiId:MSALTelemetryApiIdAcquireWithHintPromptTypeAndParameters - completionBlock:completionBlock]; + __auto_type parameters = [[MSALInteractiveTokenParameters alloc] initWithScopes:scopes]; + parameters.loginHint = loginHint; + parameters.promptType = promptType; + parameters.extraQueryParameters = extraQueryParameters; + parameters.telemetryApiId = MSALTelemetryApiIdAcquireWithHintPromptTypeAndParameters; + + [self acquireTokenWithParameters:parameters completionBlock:completionBlock]; } - (void)acquireTokenForScopes:(NSArray *)scopes @@ -468,19 +688,16 @@ - (void)acquireTokenForScopes:(NSArray *)scopes correlationId:(NSUUID *)correlationId completionBlock:(MSALCompletionBlock)completionBlock { - [self acquireTokenForScopes:scopes - extraScopesToConsent:extraScopesToConsent - account:nil - loginHint:loginHint - promptType:promptType - extraQueryParameters:extraQueryParameters - claimsRequest:nil - authority:authority - webviewType:MSALGlobalConfig.defaultWebviewType - customWebview:nil - correlationId:correlationId - apiId:MSALTelemetryApiIdAcquireWithHintPromptTypeParametersAuthorityAndCorrelationId - completionBlock:completionBlock]; + __auto_type parameters = [[MSALInteractiveTokenParameters alloc] initWithScopes:scopes]; + parameters.extraScopesToConsent = extraScopesToConsent; + parameters.loginHint = loginHint; + parameters.promptType = promptType; + parameters.extraQueryParameters = extraQueryParameters; + parameters.authority = authority; + parameters.correlationId = correlationId; + parameters.telemetryApiId = MSALTelemetryApiIdAcquireWithHintPromptTypeParametersAuthorityAndCorrelationId; + + [self acquireTokenWithParameters:parameters completionBlock:completionBlock]; } - (void)acquireTokenForScopes:(nonnull NSArray *)scopes @@ -493,19 +710,17 @@ - (void)acquireTokenForScopes:(nonnull NSArray *)scopes correlationId:(nullable NSUUID *)correlationId completionBlock:(nonnull MSALCompletionBlock)completionBlock { - [self acquireTokenForScopes:scopes - extraScopesToConsent:extraScopesToConsent - account:nil - loginHint:loginHint - promptType:promptType - extraQueryParameters:extraQueryParameters - claimsRequest:claimsRequest - authority:authority - webviewType:MSALGlobalConfig.defaultWebviewType - customWebview:nil - correlationId:correlationId - apiId:MSALTelemetryApiIdAcquireWithHintPromptTypeParametersAuthorityAndClaimsAndCorrelationId - completionBlock:completionBlock]; + __auto_type parameters = [[MSALInteractiveTokenParameters alloc] initWithScopes:scopes]; + parameters.extraScopesToConsent = extraScopesToConsent; + parameters.loginHint = loginHint; + parameters.promptType = promptType; + parameters.extraQueryParameters = extraQueryParameters; + parameters.claimsRequest = claimsRequest; + parameters.authority = authority; + parameters.correlationId = correlationId; + parameters.telemetryApiId = MSALTelemetryApiIdAcquireWithHintPromptTypeParametersAuthorityAndClaimsAndCorrelationId; + + [self acquireTokenWithParameters:parameters completionBlock:completionBlock]; } #pragma mark - Account @@ -514,20 +729,11 @@ - (void)acquireTokenForScopes:(NSArray *)scopes account:(MSALAccount *)account completionBlock:(MSALCompletionBlock)completionBlock { - [self acquireTokenForScopes:scopes - extraScopesToConsent:nil - account:account - loginHint:nil - promptType:MSALPromptTypeDefault - extraQueryParameters:nil - claimsRequest:nil - authority:nil - webviewType:MSALGlobalConfig.defaultWebviewType - customWebview:nil - correlationId:nil - apiId:MSALTelemetryApiIdAcquireWithUserPromptTypeAndParameters - completionBlock:completionBlock]; + __auto_type parameters = [[MSALInteractiveTokenParameters alloc] initWithScopes:scopes]; + parameters.account = account; + parameters.telemetryApiId = MSALTelemetryApiIdAcquireWithUserPromptTypeAndParameters; + [self acquireTokenWithParameters:parameters completionBlock:completionBlock]; } - (void)acquireTokenForScopes:(NSArray *)scopes @@ -536,19 +742,13 @@ - (void)acquireTokenForScopes:(NSArray *)scopes extraQueryParameters:(NSDictionary *)extraQueryParameters completionBlock:(MSALCompletionBlock)completionBlock { - [self acquireTokenForScopes:scopes - extraScopesToConsent:nil - account:account - loginHint:nil - promptType:promptType - extraQueryParameters:extraQueryParameters - claimsRequest:nil - authority:nil - webviewType:MSALGlobalConfig.defaultWebviewType - customWebview:nil - correlationId:nil - apiId:MSALTelemetryApiIdAcquireWithUserPromptTypeAndParameters - completionBlock:completionBlock]; + __auto_type parameters = [[MSALInteractiveTokenParameters alloc] initWithScopes:scopes]; + parameters.account = account; + parameters.promptType = promptType; + parameters.extraQueryParameters = extraQueryParameters; + parameters.telemetryApiId = MSALTelemetryApiIdAcquireWithUserPromptTypeAndParameters; + + [self acquireTokenWithParameters:parameters completionBlock:completionBlock]; } - (void)acquireTokenForScopes:(NSArray *)scopes @@ -560,20 +760,16 @@ - (void)acquireTokenForScopes:(NSArray *)scopes correlationId:(NSUUID *)correlationId completionBlock:(MSALCompletionBlock)completionBlock { - [self acquireTokenForScopes:scopes - extraScopesToConsent:extraScopesToConsent - account:account - loginHint:nil - promptType:promptType - extraQueryParameters:extraQueryParameters - claimsRequest:nil - authority:authority - webviewType:MSALGlobalConfig.defaultWebviewType - customWebview:nil - correlationId:correlationId - apiId:MSALTelemetryApiIdAcquireWithUserPromptTypeParametersAuthorityAndCorrelationId - completionBlock:completionBlock]; + __auto_type parameters = [[MSALInteractiveTokenParameters alloc] initWithScopes:scopes]; + parameters.extraScopesToConsent = extraScopesToConsent; + parameters.account = account; + parameters.promptType = promptType; + parameters.extraQueryParameters = extraQueryParameters; + parameters.authority = authority; + parameters.correlationId = correlationId; + parameters.telemetryApiId = MSALTelemetryApiIdAcquireWithUserPromptTypeParametersAuthorityAndCorrelationId; + [self acquireTokenWithParameters:parameters completionBlock:completionBlock]; } - (void)acquireTokenForScopes:(NSArray *)scopes @@ -586,20 +782,17 @@ - (void)acquireTokenForScopes:(NSArray *)scopes correlationId:(NSUUID *)correlationId completionBlock:(MSALCompletionBlock)completionBlock { - [self acquireTokenForScopes:scopes - extraScopesToConsent:extraScopesToConsent - account:account - loginHint:nil - promptType:promptType - extraQueryParameters:extraQueryParameters - claimsRequest:claimsRequest - authority:authority - webviewType:MSALGlobalConfig.defaultWebviewType - customWebview:nil - correlationId:correlationId - apiId:MSALTelemetryApiIdAcquireWithUserPromptTypeParametersAuthorityAndCorrelationId - completionBlock:completionBlock]; + __auto_type parameters = [[MSALInteractiveTokenParameters alloc] initWithScopes:scopes]; + parameters.extraScopesToConsent = extraScopesToConsent; + parameters.account = account; + parameters.promptType = promptType; + parameters.extraQueryParameters = extraQueryParameters; + parameters.claimsRequest = claimsRequest; + parameters.authority = authority; + parameters.correlationId = correlationId; + parameters.telemetryApiId = MSALTelemetryApiIdAcquireWithUserPromptTypeParametersAuthorityAndCorrelationId; + [self acquireTokenWithParameters:parameters completionBlock:completionBlock]; } #pragma mark - Silent @@ -607,319 +800,44 @@ - (void)acquireTokenForScopes:(NSArray *)scopes - (void)acquireTokenSilentWithParameters:(MSALSilentTokenParameters *)parameters completionBlock:(MSALCompletionBlock)completionBlock { - [self acquireTokenSilentForScopes:parameters.scopes - account:parameters.account - authority:parameters.authority - claimsRequest:parameters.claimsRequest - forceRefresh:parameters.forceRefresh - correlationId:parameters.correlationId - apiId:MSALTelemetryApiIdAcquireSilentWithTokenParameters - completionBlock:completionBlock]; -} - -- (void)acquireTokenSilentForScopes:(NSArray *)scopes - account:(MSALAccount *)account - completionBlock:(MSALCompletionBlock)completionBlock -{ - [self acquireTokenSilentForScopes:scopes - account:account - authority:nil - claimsRequest:nil - forceRefresh:NO - correlationId:nil - apiId:MSALTelemetryApiIdAcquireSilentWithUser - completionBlock:completionBlock]; -} - -- (void)acquireTokenSilentForScopes:(NSArray *)scopes - account:(MSALAccount *)account - authority:(MSALAuthority *)authority - completionBlock:(MSALCompletionBlock)completionBlock -{ - [self acquireTokenSilentForScopes:scopes - account:account - authority:authority - claimsRequest:nil - forceRefresh:NO - correlationId:nil - apiId:MSALTelemetryApiIdAcquireSilentWithUserAndAuthority - completionBlock:completionBlock]; -} - -- (void)acquireTokenSilentForScopes:(NSArray *)scopes - account:(MSALAccount *)account - authority:(MSALAuthority *)authority - forceRefresh:(BOOL)forceRefresh - correlationId:(NSUUID *)correlationId - completionBlock:(MSALCompletionBlock)completionBlock -{ - [self acquireTokenSilentForScopes:scopes - account:account - authority:authority - claimsRequest:nil - forceRefresh:forceRefresh - correlationId:correlationId - apiId:MSALTelemetryApiIdAcquireSilentWithUserAuthorityForceRefreshAndCorrelationId - completionBlock:completionBlock]; -} - -- (void)acquireTokenSilentForScopes:(nonnull NSArray *)scopes - account:(nonnull MSALAccount *)account - authority:(nullable MSALAuthority *)authority - claimsRequest:(nullable MSALClaimsRequest *)claimsRequest - forceRefresh:(BOOL)forceRefresh - correlationId:(nullable NSUUID *)correlationId - completionBlock:(nonnull MSALCompletionBlock)completionBlock -{ - [self acquireTokenSilentForScopes:scopes - account:account - authority:authority - claimsRequest:claimsRequest - forceRefresh:forceRefresh - correlationId:correlationId - apiId:MSALTelemetryApiIdAcquireSilentWithUserAuthorityForceRefreshAndCorrelationId - completionBlock:completionBlock]; -} - -#pragma mark - private methods - -+ (void)logOperation:(NSString *)operation - result:(MSALResult *)result - error:(NSError *)error - context:(id)ctx -{ - if (error) - { - NSString *errorDescription = error.userInfo[MSALErrorDescriptionKey]; - errorDescription = errorDescription ? errorDescription : @""; - MSID_LOG_NO_PII(MSIDLogLevelError, nil, ctx, @"%@ returning with error: (%@, %ld)", operation, error.domain, (long)error.code); - MSID_LOG_PII(MSIDLogLevelError, nil, ctx, @"%@ returning with error: (%@, %ld) %@", operation, error.domain, (long)error.code, errorDescription); - } - - if (result) - { - NSString *hashedAT = [result.accessToken msidTokenHash]; - MSID_LOG_NO_PII(MSIDLogLevelInfo, nil, ctx, @"%@ returning with at: %@ scopes:%@ expiration:%@", operation, _PII_NULLIFY(hashedAT), _PII_NULLIFY(result.scopes), result.expiresOn); - MSID_LOG_PII(MSIDLogLevelInfo, nil, ctx, @"%@ returning with at: %@ scopes:%@ expiration:%@", operation, hashedAT, result.scopes, result.expiresOn); - } -} - -- (void)acquireTokenForScopes:(NSArray *)scopes - extraScopesToConsent:(NSArray *)extraScopesToConsent - account:(MSALAccount *)account - loginHint:(NSString *)loginHint - promptType:(MSALPromptType)promptType - extraQueryParameters:(NSDictionary *)extraQueryParameters - claimsRequest:(MSALClaimsRequest *)claimsRequest - authority:(MSALAuthority *)authority - webviewType:(MSALWebviewType)webviewType - customWebview:(WKWebView *)customWebview - correlationId:(NSUUID *)correlationId - apiId:(MSALTelemetryApiId)apiId - completionBlock:(MSALCompletionBlock)completionBlock -{ - MSIDAuthority *requestAuthority = authority.msidAuthority ?: self.internalConfig.authority.msidAuthority; - NSOrderedSet *requestScopes = [[NSOrderedSet alloc] initWithArray:scopes copyItems:YES]; - NSOrderedSet *requestExtraScopes = extraScopesToConsent ? [[NSOrderedSet alloc] initWithArray:extraScopesToConsent copyItems:YES] : nil; - NSOrderedSet *requestOIDCScopes = [self.class defaultOIDCScopes]; - NSString *requestTelemetryId = [NSString stringWithFormat:@"%ld", (long)apiId]; - - NSError *msidError = nil; - - MSIDInteractiveRequestType interactiveRequestType = MSIDInteractiveRequestBrokeredType; - -#if TARGET_OS_IPHONE - if (MSALGlobalConfig.brokerAvailability == MSALBrokeredAvailabilityNone) - { - interactiveRequestType = MSIDInteractiveRequestLocalType; - } - else if (!self.internalConfig.verifiedRedirectUri.brokerCapable) - { - interactiveRequestType = MSIDInteractiveRequestLocalType; - } -#endif - MSIDInteractiveRequestParameters *params = [[MSIDInteractiveRequestParameters alloc] initWithAuthority:requestAuthority - redirectUri:self.internalConfig.verifiedRedirectUri.url.absoluteString - clientId:self.internalConfig.clientId - scopes:requestScopes - oidcScopes:requestOIDCScopes - extraScopesToConsent:requestExtraScopes - correlationId:correlationId - telemetryApiId:requestTelemetryId - supportedBrokerProtocol:MSID_BROKER_MSAL_SCHEME - requestType:interactiveRequestType - error:&msidError]; - - if (!params) - { - completionBlock(nil, [MSALErrorConverter msalErrorFromMsidError:msidError]); - return; - } - - // Configure optional parameters - BOOL accountHintPresent = (![NSString msidIsStringNilOrBlank:loginHint] || account); - - // Select account experience is undefined if user identity is passed (login_hint or account) - // Therefore, if there's user identity, we don't pass select account prompt type - if (accountHintPresent && promptType == MSALPromptTypeSelectAccount) - { - params.promptType = MSIDPromptTypePromptIfNecessary; - } - else - { - params.promptType = MSIDPromptTypeForPromptType(promptType); - } - - params.loginHint = loginHint; - params.extraAuthorizeURLQueryParameters = extraQueryParameters; - params.accountIdentifier = account.lookupAccountIdentifier; - - params.extraURLQueryParameters = self.internalConfig.extraQueryParameters.extraURLQueryParameters; - - NSMutableDictionary *extraAuthorizeURLQueryParameters = [self.internalConfig.extraQueryParameters.extraAuthorizeURLQueryParameters mutableCopy]; - [extraAuthorizeURLQueryParameters addEntriesFromDictionary:extraQueryParameters]; - params.extraAuthorizeURLQueryParameters = extraAuthorizeURLQueryParameters; - params.extraTokenRequestParameters = self.internalConfig.extraQueryParameters.extraTokenURLParameters; + MSIDAuthority *providedAuthority = parameters.authority.msidAuthority ?: self.internalConfig.authority.msidAuthority; + MSIDAuthority *requestAuthority = providedAuthority; - params.tokenExpirationBuffer = self.internalConfig.tokenExpirationBuffer; - params.extendedLifetimeEnabled = self.internalConfig.extendedLifetimeEnabled; - params.clientCapabilities = self.internalConfig.clientApplicationCapabilities; - - params.validateAuthority = _validateAuthority; - - if (params.validateAuthority - && [self shouldDisableValidationForAuthority:requestAuthority]) - { - params.validateAuthority = NO; - } - - // Configure webview - NSError *msidWebviewError = nil; - MSIDWebviewType msidWebViewType = MSIDWebviewTypeFromMSALType(webviewType, &msidWebviewError); - - if (msidWebviewError) - { - completionBlock(nil, [MSALErrorConverter msalErrorFromMsidError:msidWebviewError]); - return; - } - - params.webviewType = msidWebViewType; - params.telemetryWebviewType = MSALStringForMSALWebviewType(webviewType); - params.customWebview = customWebview ?: self.customWebview; - params.claimsRequest = claimsRequest.msidClaimsRequest; - - MSID_LOG_NO_PII(MSIDLogLevelInfo, nil, params, - @"-[MSALPublicClientApplication acquireTokenForScopes:%@\n" - " extraScopesToConsent:%@\n" - " account:%@\n" - " loginHint:%@\n" - " promptType:%@\n" - " extraQueryParameters:%@\n" - " authority:%@\n" - " webviewType:%@\n" - " customWebview:%@\n" - " correlationId:%@\n" - " capabilities:%@\n" - " claimsRequest:%@]", - - _PII_NULLIFY(scopes), _PII_NULLIFY(extraScopesToConsent), _PII_NULLIFY(account.homeAccountId), _PII_NULLIFY(loginHint), MSALStringForPromptType(promptType), extraQueryParameters, _PII_NULLIFY(authority), MSALStringForMSALWebviewType(webviewType), params.customWebview, correlationId, self.internalConfig.clientApplicationCapabilities, claimsRequest); - MSID_LOG_PII(MSIDLogLevelInfo, nil, params, - @"-[MSALPublicClientApplication acquireTokenForScopes:%@\n" - " extraScopesToConsent:%@\n" - " account:%@\n" - " loginHint:%@\n" - " promptType:%@\n" - " extraQueryParameters:%@\n" - " authority:%@\n" - " webviewType:%@\n" - " customWebview:%@\n" - " correlationId:%@\n" - " capabilities:%@\n" - " claimsRequest:%@]", - scopes, extraScopesToConsent, account.homeAccountId, loginHint, MSALStringForPromptType(promptType), extraQueryParameters, authority, MSALStringForMSALWebviewType(webviewType), params.customWebview, correlationId, self.internalConfig.clientApplicationCapabilities, claimsRequest); - - MSALCompletionBlock block = ^(MSALResult *result, NSError *msidError) + // This is meant to avoid developer error, when they configure PCA with e.g. AAD authority, but pass B2C authority here + // Authority type in PCA and parameters should match + if (![self.msalOauth2Provider isSupportedAuthority:requestAuthority]) { - NSError *msalError = [MSALErrorConverter msalErrorFromMsidError:msidError]; - [MSALPublicClientApplication logOperation:@"acquireToken" result:result error:msalError context:params]; - - if ([NSThread isMainThread]) - { - completionBlock(result, msalError); - } - else + if (completionBlock) { - dispatch_async(dispatch_get_main_queue(), ^{ - completionBlock(result, msalError); - }); + NSError *msidError = MSIDCreateError(MSIDErrorDomain, MSIDErrorInvalidDeveloperParameter, @"Unsupported authority type. Please configure MSALPublicClientApplication with the same authority type", nil, nil, nil, nil, nil); + NSError *msalError = [MSALErrorConverter msalErrorFromMsidError:msidError]; + completionBlock(nil, msalError); } - }; - - NSError *requestError = nil; - - MSIDOauth2Factory *oauth2Factory = [MSALOauth2FactoryProducer msidOauth2FactoryForAuthority:self.internalConfig.authority.url context:nil error:&requestError]; - - if (!oauth2Factory) - { - block(nil, requestError); - return; - } - - MSIDDefaultTokenRequestProvider *tokenRequestProvider = [[MSIDDefaultTokenRequestProvider alloc] initWithOauthFactory:oauth2Factory - defaultAccessor:_tokenCache - tokenResponseValidator:[MSIDDefaultTokenResponseValidator new]]; - - id controller = [MSIDRequestControllerFactory interactiveControllerForParameters:params tokenRequestProvider:tokenRequestProvider error:&requestError]; - - if (!controller) - { - block(nil, requestError); + return; } - - [controller acquireToken:^(MSIDTokenResult * _Nullable result, NSError * _Nullable error) { - - if (error) - { - block(nil, error); - return; - } - - NSError *resultError = nil; - MSALResult *msalResult = [MSALResult resultWithTokenResult:result error:&resultError]; - block(msalResult, resultError); - }]; -} - -- (void)acquireTokenSilentForScopes:(NSArray *)scopes - account:(MSALAccount *)account - authority:(MSALAuthority *)authority - claimsRequest:(MSALClaimsRequest *)claimsRequest - forceRefresh:(BOOL)forceRefresh - correlationId:(NSUUID *)correlationId - apiId:(MSALTelemetryApiId)apiId - completionBlock:(MSALCompletionBlock)completionBlock -{ - - MSIDAuthority *msidAuthority = authority.msidAuthority ?: self.internalConfig.authority.msidAuthority; BOOL shouldValidate = _validateAuthority; - if (shouldValidate && [self shouldDisableValidationForAuthority:msidAuthority]) + if (shouldValidate && [self shouldExcludeValidationForAuthority:requestAuthority]) { shouldValidate = NO; } - + /* In the acquire token silent call we assume developer wants to get access token for account's home tenant, if authority is a common, organizations or consumers authority. + TODO: update instanceAware parameter to the instanceAware in config */ NSError *authorityError = nil; - msidAuthority = [MSIDAuthorityFactory authorityWithRawTenant:account.homeAccountId.tenantId msidAuthority:msidAuthority context:nil error:&authorityError]; + requestAuthority = [self.msalOauth2Provider issuerAuthorityWithAccount:parameters.account + requestAuthority:requestAuthority + instanceAware:NO + error:&authorityError]; - if (!msidAuthority) + if (!requestAuthority) { - MSID_LOG_ERROR(nil, @"Encountered an error when updating authority: %ld, %@", (long)authorityError.code, authorityError.domain); + MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"Encountered an error when updating authority: %ld, %@", (long)authorityError.code, authorityError.domain); if (completionBlock) { @@ -930,98 +848,182 @@ - (void)acquireTokenSilentForScopes:(NSArray *)scopes return; } - NSOrderedSet *requestScopes = [[NSOrderedSet alloc] initWithArray:scopes copyItems:YES]; - NSOrderedSet *requestOIDCScopes = [self.class defaultOIDCScopes]; - NSString *requestTelemetryId = [NSString stringWithFormat:@"%ld", (long)apiId]; - NSError *msidError = nil; - + // add known authorities here. - MSIDRequestParameters *params = [[MSIDRequestParameters alloc] initWithAuthority:msidAuthority + MSIDRequestParameters *msidParams = [[MSIDRequestParameters alloc] initWithAuthority:requestAuthority redirectUri:self.internalConfig.verifiedRedirectUri.url.absoluteString clientId:self.internalConfig.clientId - scopes:requestScopes - oidcScopes:requestOIDCScopes - correlationId:correlationId - telemetryApiId:requestTelemetryId + scopes:[[NSOrderedSet alloc] initWithArray:parameters.scopes copyItems:YES] + oidcScopes:[self.class defaultOIDCScopes] + correlationId:parameters.correlationId + telemetryApiId:[NSString stringWithFormat:@"%ld", (long)parameters.telemetryApiId] error:&msidError]; - - if (!params) + + if (!msidParams) { completionBlock(nil, [MSALErrorConverter msalErrorFromMsidError:msidError]); return; } - + // Set optional params - params.accountIdentifier = account.lookupAccountIdentifier; - params.validateAuthority = shouldValidate; - params.extendedLifetimeEnabled = self.internalConfig.extendedLifetimeEnabled; - params.clientCapabilities = self.internalConfig.clientApplicationCapabilities; - params.extraURLQueryParameters = self.internalConfig.extraQueryParameters.extraURLQueryParameters; - params.extraTokenRequestParameters = self.internalConfig.extraQueryParameters.extraTokenURLParameters; - params.tokenExpirationBuffer = self.internalConfig.tokenExpirationBuffer; - params.claimsRequest = claimsRequest.msidClaimsRequest; - - MSID_LOG_NO_PII(MSIDLogLevelInfo, nil, params, - @"-[MSALPublicClientApplication acquireTokenSilentForScopes:%@\n" - " account:%@\n" - " authority:%@\n" - " forceRefresh:%@\n" - " correlationId:%@\n" - " capabilities:%@\n" - " claimsRequest:%@]", - _PII_NULLIFY(scopes), _PII_NULLIFY(account), _PII_NULLIFY(authority), forceRefresh ? @"Yes" : @"No", correlationId, self.internalConfig.clientApplicationCapabilities, claimsRequest); - - MSID_LOG_PII(MSIDLogLevelInfo, nil, params, + msidParams.accountIdentifier = parameters.account.lookupAccountIdentifier; + msidParams.validateAuthority = shouldValidate; + msidParams.extendedLifetimeEnabled = self.internalConfig.extendedLifetimeEnabled; + msidParams.clientCapabilities = self.internalConfig.clientApplicationCapabilities; + msidParams.extraURLQueryParameters = self.internalConfig.extraQueryParameters.extraURLQueryParameters; + msidParams.extraTokenRequestParameters = self.internalConfig.extraQueryParameters.extraTokenURLParameters; + msidParams.tokenExpirationBuffer = self.internalConfig.tokenExpirationBuffer; + msidParams.claimsRequest = parameters.claimsRequest.msidClaimsRequest; + msidParams.providedAuthority = providedAuthority; + + MSID_LOG_WITH_CTX_PII(MSIDLogLevelInfo, msidParams, @"-[MSALPublicClientApplication acquireTokenSilentForScopes:%@\n" - " account:%@\n" - " authority:%@\n" - " forceRefresh:%@\n" - " correlationId:%@\n" - " capabilities:%@\n" - " claimsRequest:%@]", - scopes, account, _PII_NULLIFY(authority), forceRefresh ? @"Yes" : @"No", correlationId, self.internalConfig.clientApplicationCapabilities, claimsRequest); - + " account:%@\n" + " authority:%@\n" + " validateAuthority:%@\n" + " forceRefresh:%@\n" + " correlationId:%@\n" + " capabilities:%@\n" + " claimsRequest:%@]", + parameters.scopes, + MSID_PII_LOG_EMAIL(parameters.account), + parameters.authority, + shouldValidate ? @"Yes" : @"No", + parameters.forceRefresh ? @"Yes" : @"No", + parameters.correlationId, + self.internalConfig.clientApplicationCapabilities, + parameters.claimsRequest); + MSALCompletionBlock block = ^(MSALResult *result, NSError *msidError) { - NSError *msalError = [MSALErrorConverter msalErrorFromMsidError:msidError]; - [MSALPublicClientApplication logOperation:@"acquireTokenSilent" result:result error:msalError context:params]; + NSError *msalError = [MSALErrorConverter msalErrorFromMsidError:msidError classifyErrors:YES msalOauth2Provider:self.msalOauth2Provider]; + [MSALPublicClientApplication logOperation:@"acquireTokenSilent" result:result error:msalError context:msidParams]; completionBlock(result, msalError); }; - - NSError *requestError = nil; - MSIDOauth2Factory *oauth2Factory = [MSALOauth2FactoryProducer msidOauth2FactoryForAuthority:self.internalConfig.authority.url context:nil error:&requestError]; - - if (!oauth2Factory) - { - block(nil, requestError); - return; - } - - MSIDDefaultTokenRequestProvider *tokenRequestProvider = [[MSIDDefaultTokenRequestProvider alloc] initWithOauthFactory:oauth2Factory - defaultAccessor:_tokenCache + + MSIDDefaultTokenRequestProvider *tokenRequestProvider = [[MSIDDefaultTokenRequestProvider alloc] initWithOauthFactory:self.msalOauth2Provider.msidOauth2Factory + defaultAccessor:self.tokenCache + accountMetadataAccessor:self.accountMetadataCache tokenResponseValidator:[MSIDDefaultTokenResponseValidator new]]; - - id requestController = [MSIDRequestControllerFactory silentControllerForParameters:params forceRefresh:forceRefresh tokenRequestProvider:tokenRequestProvider error:&requestError]; - +#if TARGET_OS_OSX + tokenRequestProvider.externalCacheSeeder = self.externalCacheSeeder; +#endif + + NSError *requestError = nil; + id requestController = [MSIDRequestControllerFactory silentControllerForParameters:msidParams forceRefresh:parameters.forceRefresh tokenRequestProvider:tokenRequestProvider error:&requestError]; + if (!requestController) { block(nil, requestError); return; } - + [requestController acquireToken:^(MSIDTokenResult * _Nullable result, NSError * _Nullable error) { - + if (error) { block(nil, error); return; } - + NSError *resultError = nil; - MSALResult *msalResult = [MSALResult resultWithTokenResult:result error:&resultError]; + MSALResult *msalResult = [self.msalOauth2Provider resultWithTokenResult:result error:&resultError]; + [self updateExternalAccountsWithResult:msalResult context:msidParams]; block(msalResult, resultError); }]; + +} + +- (void)acquireTokenSilentForScopes:(NSArray *)scopes + account:(MSALAccount *)account + completionBlock:(MSALCompletionBlock)completionBlock +{ + __auto_type parameters = [[MSALSilentTokenParameters alloc] initWithScopes:scopes account:account]; + parameters.telemetryApiId = MSALTelemetryApiIdAcquireSilentWithUser; + + [self acquireTokenSilentWithParameters:parameters completionBlock:completionBlock]; +} + +- (void)acquireTokenSilentForScopes:(NSArray *)scopes + account:(MSALAccount *)account + authority:(MSALAuthority *)authority + completionBlock:(MSALCompletionBlock)completionBlock +{ + __auto_type parameters = [[MSALSilentTokenParameters alloc] initWithScopes:scopes account:account]; + parameters.authority = authority; + parameters.telemetryApiId = MSALTelemetryApiIdAcquireSilentWithUserAndAuthority; + + [self acquireTokenSilentWithParameters:parameters completionBlock:completionBlock]; +} + +- (void)acquireTokenSilentForScopes:(NSArray *)scopes + account:(MSALAccount *)account + authority:(MSALAuthority *)authority + forceRefresh:(BOOL)forceRefresh + correlationId:(NSUUID *)correlationId + completionBlock:(MSALCompletionBlock)completionBlock +{ + __auto_type parameters = [[MSALSilentTokenParameters alloc] initWithScopes:scopes account:account]; + parameters.authority = authority; + parameters.forceRefresh = forceRefresh; + parameters.correlationId = correlationId; + parameters.telemetryApiId = MSALTelemetryApiIdAcquireSilentWithUserAuthorityForceRefreshAndCorrelationId; + + [self acquireTokenSilentWithParameters:parameters completionBlock:completionBlock]; +} + +- (void)acquireTokenSilentForScopes:(nonnull NSArray *)scopes + account:(nonnull MSALAccount *)account + authority:(nullable MSALAuthority *)authority + claimsRequest:(nullable MSALClaimsRequest *)claimsRequest + forceRefresh:(BOOL)forceRefresh + correlationId:(nullable NSUUID *)correlationId + completionBlock:(nonnull MSALCompletionBlock)completionBlock +{ + __auto_type parameters = [[MSALSilentTokenParameters alloc] initWithScopes:scopes account:account]; + parameters.authority = authority; + parameters.claimsRequest = claimsRequest; + parameters.forceRefresh = forceRefresh; + parameters.correlationId = correlationId; + parameters.telemetryApiId = MSALTelemetryApiIdAcquireSilentWithUserAuthorityClaimsForceRefreshAndCorrelationId; + + [self acquireTokenSilentWithParameters:parameters completionBlock:completionBlock]; +} + +#pragma mark - private methods + ++ (void)logOperation:(NSString *)operation + result:(MSALResult *)result + error:(NSError *)error + context:(id)ctx +{ + if (error) + { + NSString *errorDescription = error.userInfo[MSALErrorDescriptionKey]; + errorDescription = errorDescription ? errorDescription : @""; + MSID_LOG_WITH_CTX_PII(MSIDLogLevelError, ctx, @"%@ returning with error: (%@, %ld) %@", operation, error.domain, (long)error.code, MSID_PII_LOG_MASKABLE(errorDescription)); + } + + if (result) + { + NSString *hashedAT = [result.accessToken msidTokenHash]; + MSID_LOG_WITH_CTX_PII(MSIDLogLevelInfo, ctx, @"%@ returning with at: %@ scopes:%@ expiration:%@", operation, hashedAT, result.scopes, result.expiresOn); + } +} + +- (void)updateExternalAccountsWithResult:(MSALResult *)result context:(id)context +{ + if (result && self.externalAccountHandler) + { + NSError *updateError = nil; + BOOL updateResult = [self.externalAccountHandler updateWithResult:result error:&updateError]; + + if (!updateResult) + { + MSID_LOG_WITH_CTX_PII(MSIDLogLevelWarning, context, @"Failed to update external account with result %@", MSID_PII_LOG_MASKABLE(updateError)); + } + } } #pragma mark - Remove account from cache @@ -1047,35 +1049,31 @@ - (BOOL)removeAccount:(MSALAccount *)account if (error) *error = [MSALErrorConverter msalErrorFromMsidError:msidError]; return NO; } - - NSError *metadataError = nil; - // If we remove account, we want this app to be also disassociated from foci token, so that user cannot sign in silently again after signing out - // Therefore, we update app metadata to not have family id for this app after signout - - NSURL *authorityURL = [NSURL msidURLWithEnvironment:account.environment tenant:account.homeAccountId.tenantId]; - MSIDAuthority *authority = [MSIDAuthorityFactory authorityFromUrl:authorityURL context:nil error:nil]; - - BOOL metadataResult = [self.tokenCache updateAppMetadataWithFamilyId:@"" - clientId:self.internalConfig.clientId - authority:authority - context:nil - error:&metadataError]; - - if (!metadataResult) + + if (self.externalAccountHandler) { - MSID_LOG_WARN(nil, @"Failed to update app metadata when removing account %ld, %@", (long)metadataError.code, metadataError.domain); - MSID_LOG_WARN(nil, @"Failed to update app metadata when removing account %@", metadataError); + NSError *externalError = nil; + result &= [self.externalAccountHandler removeAccount:account error:&externalError]; + + if (externalError && error) + { + *error = [MSALErrorConverter msalErrorFromMsidError:externalError]; + } } - return result; + if (self.accountMetadataCache && ![self.accountMetadataCache clearForHomeAccountId:account.identifier + clientId:self.internalConfig.clientId + context:nil + error:error]) + { + return NO; + } + + return [self.msalOauth2Provider removeAdditionalAccountInfo:account + error:error]; } -@end - - -@implementation MSALPublicClientApplication (Internal) - -- (BOOL)shouldDisableValidationForAuthority:(MSIDAuthority *)authority +- (BOOL)shouldExcludeValidationForAuthority:(MSIDAuthority *)authority { if (self.internalConfig.knownAuthorities) { diff --git a/MSAL/src/MSALResult+Internal.h b/MSAL/src/MSALResult+Internal.h index 9a3886ae79..44825a68f6 100644 --- a/MSAL/src/MSALResult+Internal.h +++ b/MSAL/src/MSALResult+Internal.h @@ -27,24 +27,12 @@ #import "MSALResult.h" -@class MSIDAccessToken; -@class MSIDIdToken; -@class MSIDClientInfo; @class MSIDTokenResult; @interface MSALResult (Internal) -+ (MSALResult *)resultWithTokenResult:(MSIDTokenResult *)tokenResult - error:(NSError **)error; - -+ (MSALResult *)resultWithAccessToken:(NSString *)accessToken - expiresOn:(NSDate *)expiresOn - isExtendedLifetimeToken:(BOOL)isExtendedLifetimeToken - tenantId:(NSString *)tenantId - account:(MSALAccount *)account - idToken:(NSString *)idToken - uniqueId:(NSString *)uniqueId - scopes:(NSArray *)scopes - authority:(MSALAuthority *)authority; ++ (MSALResult *)resultWithMSIDTokenResult:(MSIDTokenResult *)tokenResult + authority:(MSALAuthority *)authority + error:(NSError **)error; @end diff --git a/MSAL/src/MSALResult.m b/MSAL/src/MSALResult.m index 8bad23ada2..e5811e361e 100644 --- a/MSAL/src/MSALResult.m +++ b/MSAL/src/MSALResult.m @@ -36,10 +36,12 @@ #import "MSALAuthority.h" #import "MSIDAuthority.h" #import "MSIDAccountIdentifier.h" -#import "MSALAuthorityFactory.h" #import "MSIDTokenResult.h" #import "MSIDAccount.h" #import "MSIDAADV2IdTokenClaims.h" +#import "MSALAccountsProvider.h" +#import "MSALTenantProfile.h" +#import "MSALTenantProfile+Internal.h" @implementation MSALResult @@ -51,11 +53,13 @@ + (MSALResult *)resultWithAccessToken:(NSString *)accessToken expiresOn:(NSDate *)expiresOn isExtendedLifetimeToken:(BOOL)isExtendedLifetimeToken tenantId:(NSString *)tenantId + tenantProfile:(MSALTenantProfile *)tenantProfile account:(MSALAccount *)account idToken:(NSString *)idToken uniqueId:(NSString *)uniqueId scopes:(NSArray *)scopes authority:(MSALAuthority *)authority + correlationId:(NSUUID *)correlationId { MSALResult *result = [MSALResult new]; @@ -63,70 +67,64 @@ + (MSALResult *)resultWithAccessToken:(NSString *)accessToken result->_expiresOn = expiresOn; result->_extendedLifeTimeToken = isExtendedLifetimeToken; result->_tenantId = tenantId; + result->_tenantProfile = tenantProfile; result->_account = account; result->_idToken = idToken; result->_uniqueId = uniqueId; result->_scopes = scopes; result->_authority = authority; + result->_correlationId = correlationId; return result; } -+ (MSALResult *)resultWithTokenResult:(MSIDTokenResult *)tokenResult - error:(NSError **)error ++ (MSALResult *)resultWithMSIDTokenResult:(MSIDTokenResult *)tokenResult + authority:(MSALAuthority *)authority + error:(NSError **)error { if (!tokenResult) { MSIDFillAndLogError(error, MSIDErrorInternal, @"Nil token result provided", nil); return nil; } - - MSIDAccount *resultAccount = tokenResult.account; - NSError *claimsError = nil; - MSIDAADV2IdTokenClaims *claims = [[MSIDAADV2IdTokenClaims alloc] initWithRawIdToken:tokenResult.rawIdToken error:&claimsError]; + + MSIDIdTokenClaims *claims = [[MSIDIdTokenClaims alloc] initWithRawIdToken:tokenResult.rawIdToken error:error]; if (!claims) { - if (error) *error = claimsError; - return nil; } - NSString *tenantId = claims.realm; - - MSALAccount *account = [[MSALAccount alloc] initWithUsername:resultAccount.username - name:resultAccount.name - homeAccountId:resultAccount.accountIdentifier.homeAccountId - localAccountId:resultAccount.localAccountId - environment:tokenResult.authority.environment - tenantId:tenantId]; - - NSError *authorityError = nil; - MSALAuthority *authority = [MSALAuthorityFactory authorityFromUrl:tokenResult.authority.url - validateFormat:NO - rawTenant:tenantId - context:nil - error:&authorityError]; - if (!authority) { - MSID_LOG_NO_PII(MSIDLogLevelWarning, nil, nil, @"Invalid authority"); - MSID_LOG_PII(MSIDLogLevelWarning, nil, nil, @"Invalid authority, error %@", authorityError); - - if (error) *error = authorityError; - + MSIDFillAndLogError(error, MSIDErrorInternal, @"Nil authority in the result provided", nil); return nil; } - + + MSALTenantProfile *tenantProfile = [[MSALTenantProfile alloc] initWithIdentifier:tokenResult.account.localAccountId + tenantId:tokenResult.account.realm + environment:tokenResult.account.environment + isHomeTenantProfile:tokenResult.account.isHomeTenantAccount + claims:claims.jsonDictionary]; + + MSALAccount *account = [[MSALAccount alloc] initWithMSIDAccount:tokenResult.account createTenantProfile:NO]; + + if (tokenResult.account.isHomeTenantAccount) + { + account.accountClaims = claims.jsonDictionary; + } + return [self resultWithAccessToken:tokenResult.accessToken.accessToken expiresOn:tokenResult.accessToken.expiresOn isExtendedLifetimeToken:tokenResult.extendedLifeTimeToken - tenantId:tenantId + tenantId:tenantProfile.tenantId + tenantProfile:tenantProfile account:account idToken:tokenResult.rawIdToken - uniqueId:resultAccount.localAccountId + uniqueId:tenantProfile.identifier scopes:[tokenResult.accessToken.scopes array] - authority:authority]; + authority:authority + correlationId:tokenResult.correlationId]; } @end diff --git a/MSAL/src/MSALSilentTokenParameters.m b/MSAL/src/MSALSilentTokenParameters.m index 9d94131a6b..b8da325ad4 100644 --- a/MSAL/src/MSALSilentTokenParameters.m +++ b/MSAL/src/MSALSilentTokenParameters.m @@ -30,6 +30,8 @@ @implementation MSALSilentTokenParameters +@synthesize telemetryApiId; + - (instancetype)initWithScopes:(NSArray *)scopes account:(MSALAccount *)account { @@ -37,6 +39,7 @@ - (instancetype)initWithScopes:(NSArray *)scopes if (self) { self.account = account; + self.telemetryApiId = MSALTelemetryApiIdAcquireSilentWithTokenParameters; } return self; } diff --git a/MSAL/src/MSALTelemetryApiId.h b/MSAL/src/MSALTelemetryApiId.h index 45de91d234..bb4eca6171 100644 --- a/MSAL/src/MSALTelemetryApiId.h +++ b/MSAL/src/MSALTelemetryApiId.h @@ -36,6 +36,8 @@ typedef NS_ENUM(NSInteger, MSALTelemetryApiId) MSALTelemetryApiIdAcquireSilentWithUser = 30, MSALTelemetryApiIdAcquireSilentWithUserAndAuthority = 31, MSALTelemetryApiIdAcquireSilentWithUserAuthorityForceRefreshAndCorrelationId = 32, - MSALTelemetryApiIdAcquireSilentWithTokenParameters = 33 + MSALTelemetryApiIdAcquireSilentWithUserAuthorityClaimsForceRefreshAndCorrelationId = 33, + MSALTelemetryApiIdAcquireSilentWithTokenParameters = 34 + }; diff --git a/MSAL/src/instance/MSALAuthorityFactory.h b/MSAL/src/MSALTenantProfile+Internal.h similarity index 65% rename from MSAL/src/instance/MSALAuthorityFactory.h rename to MSAL/src/MSALTenantProfile+Internal.h index 37d6b582c6..4d5d785dbd 100644 --- a/MSAL/src/instance/MSALAuthorityFactory.h +++ b/MSAL/src/MSALTenantProfile+Internal.h @@ -25,20 +25,26 @@ // //------------------------------------------------------------------------------ -#import - @class MSALAuthority; -@interface MSALAuthorityFactory : NSObject +#import "MSALTenantProfile.h" + +NS_ASSUME_NONNULL_BEGIN -+ (nullable MSALAuthority *)authorityFromUrl:(nonnull NSURL *)url - context:(nullable id)context - error:(NSError * _Nullable __autoreleasing * _Nullable)error; +@interface MSALTenantProfile () -+ (nullable MSALAuthority *)authorityFromUrl:(nonnull NSURL *)url - validateFormat:(BOOL)validateFormat - rawTenant:(nullable NSString *)rawTenant - context:(nullable id)context - error:(NSError * _Nullable __autoreleasing * _Nullable)error; +@property (readwrite, nullable) NSString *identifier; +@property (readwrite, nullable) NSString *environment; +@property (readwrite, nullable) NSString *tenantId; +@property (readwrite) BOOL isHomeTenantProfile; +@property (readwrite, nullable) NSDictionary *claims; + +- (instancetype)initWithIdentifier:(nonnull NSString *)identifier + tenantId:(nonnull NSString *)tenantId + environment:(nonnull NSString *)environment + isHomeTenantProfile:(BOOL)isHomeTenantProfile + claims:(nullable NSDictionary *)claims; @end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/src/MSALTenantProfile.m b/MSAL/src/MSALTenantProfile.m new file mode 100644 index 0000000000..4ddb8fb9e2 --- /dev/null +++ b/MSAL/src/MSALTenantProfile.m @@ -0,0 +1,66 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALTenantProfile.h" +#import "MSALTenantProfile+Internal.h" + +@implementation MSALTenantProfile + +- (instancetype)initWithIdentifier:(nonnull NSString *)identifier + tenantId:(nonnull NSString *)tenantId + environment:(nonnull NSString *)environment + isHomeTenantProfile:(BOOL)isHomeTenantProfile + claims:(nullable NSDictionary *)claims +{ + self = [super init]; + + if (self) + { + _identifier = identifier; + _tenantId = tenantId; + _environment = environment; + _isHomeTenantProfile = isHomeTenantProfile; + _claims = claims; + } + + return self; +} + +#pragma mark - NSCopying + +- (instancetype)copyWithZone:(NSZone *)zone +{ + MSALTenantProfile *tenantProfile = [[self.class allocWithZone:zone] init]; + tenantProfile->_identifier = [_identifier copyWithZone:zone]; + tenantProfile->_tenantId = [_tenantId copyWithZone:zone]; + tenantProfile->_environment = [_environment copyWithZone:zone]; + tenantProfile->_isHomeTenantProfile = _isHomeTenantProfile; + tenantProfile->_claims = [[NSDictionary alloc] initWithDictionary:_claims copyItems:YES]; + return tenantProfile; +} + +@end diff --git a/MSAL/src/MSALTokenParameters+Internal.h b/MSAL/src/MSALTokenParameters+Internal.h index 04cba4469b..0533203573 100644 --- a/MSAL/src/MSALTokenParameters+Internal.h +++ b/MSAL/src/MSALTokenParameters+Internal.h @@ -26,7 +26,7 @@ //------------------------------------------------------------------------------ #import "MSALTokenParameters.h" - +#import "MSALTelemetryApiId.h" NS_ASSUME_NONNULL_BEGIN @@ -41,6 +41,8 @@ NS_ASSUME_NONNULL_BEGIN */ - (instancetype)initWithScopes:(NSArray *)scopes NS_DESIGNATED_INITIALIZER; +@property MSALTelemetryApiId telemetryApiId; + @end NS_ASSUME_NONNULL_END diff --git a/MSAL/src/MSAL_Internal.h b/MSAL/src/MSAL_Internal.h index ce7cf593d2..f67334e8cb 100644 --- a/MSAL/src/MSAL_Internal.h +++ b/MSAL/src/MSAL_Internal.h @@ -26,8 +26,8 @@ //------------------------------------------------------------------------------ #define MSAL_VER_HIGH 0 -#define MSAL_VER_LOW 4 -#define MSAL_VER_PATCH 3 +#define MSAL_VER_LOW 5 +#define MSAL_VER_PATCH 0 #define STR_HELPER(x) #x #define STR(x) STR_HELPER(x) diff --git a/MSAL/src/configuration/MSALCacheConfig.m b/MSAL/src/configuration/MSALCacheConfig.m index a397cd1487..6d6c6b527e 100644 --- a/MSAL/src/configuration/MSALCacheConfig.m +++ b/MSAL/src/configuration/MSALCacheConfig.m @@ -30,8 +30,16 @@ #if TARGET_OS_IPHONE #import "MSIDKeychainTokenCache.h" +#else +#import "MSIDMacKeychainTokenCache.h" #endif +@interface MSALCacheConfig() + +@property (nonatomic, readwrite) NSArray> *externalAccountProviders; + +@end + @implementation MSALCacheConfig - (instancetype)initWithKeychainSharingGroup:(NSString *)keychainSharingGroup @@ -39,9 +47,7 @@ - (instancetype)initWithKeychainSharingGroup:(NSString *)keychainSharingGroup self = [super init]; if (self) { -#if TARGET_OS_IPHONE _keychainSharingGroup = keychainSharingGroup; -#endif } return self; } @@ -51,17 +57,13 @@ + (NSString *)defaultKeychainSharingGroup #if TARGET_OS_IPHONE return MSIDKeychainTokenCache.defaultKeychainGroup; #else - return nil; + return MSIDMacKeychainTokenCache.defaultKeychainGroup; #endif } + (instancetype)defaultConfig { -#if TARGET_OS_IPHONE - return [[self.class alloc] initWithKeychainSharingGroup:MSIDKeychainTokenCache.defaultKeychainGroup]; -#else - return [[self.class alloc] initWithKeychainSharingGroup:nil]; -#endif + return [[self.class alloc] initWithKeychainSharingGroup:self.defaultKeychainSharingGroup]; } #pragma mark - NSCopying @@ -69,7 +71,25 @@ + (instancetype)defaultConfig - (id)copyWithZone:(NSZone *)zone { NSString *keychainSharingGroup = [_keychainSharingGroup copyWithZone:zone]; - return [[self.class alloc] initWithKeychainSharingGroup:keychainSharingGroup]; + MSALCacheConfig *copiedConfig = [[self.class alloc] initWithKeychainSharingGroup:keychainSharingGroup]; + copiedConfig->_externalAccountProviders = [[NSArray alloc] initWithArray:_externalAccountProviders copyItems:NO]; +#if !TARGET_OS_IPHONE + copiedConfig->_serializedADALCache = _serializedADALCache; +#endif + return copiedConfig; +} + +- (void)addExternalAccountProvider:(id)externalAccountProvider +{ + if (!externalAccountProvider) + { + return; + } + + NSMutableArray *newExternalProviders = [NSMutableArray new]; + [newExternalProviders addObjectsFromArray:self.externalAccountProviders]; + [newExternalProviders addObject:externalAccountProvider]; + self.externalAccountProviders = newExternalProviders; } @end diff --git a/MSAL/src/configuration/MSALLoggerConfig+Internal.h b/MSAL/src/configuration/MSALLoggerConfig+Internal.h index a6c31d4763..d90d53282d 100644 --- a/MSAL/src/configuration/MSALLoggerConfig+Internal.h +++ b/MSAL/src/configuration/MSALLoggerConfig+Internal.h @@ -31,6 +31,6 @@ + (instancetype)sharedInstance; -@property MSALLogCallback callback; +@property (nonatomic, copy) MSALLogCallback callback; @end diff --git a/MSAL/src/configuration/MSALPublicClientApplicationConfig.m b/MSAL/src/configuration/MSALPublicClientApplicationConfig.m index 8632181b02..f4eca161e1 100644 --- a/MSAL/src/configuration/MSALPublicClientApplicationConfig.m +++ b/MSAL/src/configuration/MSALPublicClientApplicationConfig.m @@ -31,6 +31,7 @@ #import "MSALExtraQueryParameters.h" #import "MSALSliceConfig.h" #import "MSALCacheConfig+Internal.h" +#import "MSIDConstants.h" static double defaultTokenExpirationBuffer = 300; //in seconds, ensures catching of clock differences between the server and the device @@ -39,8 +40,6 @@ @implementation MSALPublicClientApplicationConfig MSALSliceConfig *_sliceConfig; } -static NSString *const s_defaultAuthorityUrlString = @"https://login.microsoftonline.com/common"; - - (instancetype)initWithClientId:(NSString *)clientId { return [self initWithClientId:clientId redirectUri:nil authority:nil]; @@ -54,7 +53,7 @@ - (instancetype)initWithClientId:(NSString *)clientId redirectUri:(nullable NSSt _clientId = clientId; _redirectUri = redirectUri; - NSURL *authorityURL = [NSURL URLWithString:s_defaultAuthorityUrlString]; + NSURL *authorityURL = [NSURL URLWithString:MSID_DEFAULT_AAD_AUTHORITY]; _authority = authority ?: [[MSALAADAuthority alloc] initWithURL:authorityURL error:nil]; _extraQueryParameters = [[MSALExtraQueryParameters alloc] init]; diff --git a/MSAL/src/configuration/MSALTelemetryConfig.m b/MSAL/src/configuration/MSALTelemetryConfig.m index d3c8dd7524..9e353f9082 100644 --- a/MSAL/src/configuration/MSALTelemetryConfig.m +++ b/MSAL/src/configuration/MSALTelemetryConfig.m @@ -26,11 +26,17 @@ //------------------------------------------------------------------------------ #import "MSALTelemetryConfig+Internal.h" - #import "MSIDTelemetryEventInterface.h" -#import "MSALDefaultDispatcher.h" #import "MSIDTelemetry.h" #import "MSIDTelemetry+Internal.h" +#import "MSALTelemetryEventsObservingProxy.h" +#import "MSIDAggregatedDispatcher.h" + +@interface MSALTelemetryConfig() + +@property (nonatomic) MSALTelemetryEventsObservingProxy *proxyObserver; + +@end @implementation MSALTelemetryConfig @@ -40,30 +46,44 @@ + (instancetype)sharedInstance static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [[self.class alloc] init]; + [sharedInstance initDispatchers]; }); return sharedInstance; } -- (BOOL)piiEnabled { return MSIDTelemetry.sharedInstance.piiEnabled; } -- (void)setPiiEnabled:(BOOL)piiEnabled { [[MSIDTelemetry sharedInstance] setPiiEnabled:piiEnabled]; } +- (BOOL)piiEnabled +{ + return MSIDTelemetry.sharedInstance.piiEnabled; +} -- (void)addDispatcher:(nonnull id)dispatcher setTelemetryOnFailure:(BOOL)setTelemetryOnFailure +- (void)setPiiEnabled:(BOOL)piiEnabled { - MSALDefaultDispatcher *telemetryDispatcher = [[MSALDefaultDispatcher alloc] initWithDispatcher:dispatcher - setTelemetryOnFailure:setTelemetryOnFailure]; - - [[MSIDTelemetry sharedInstance] addDispatcher:telemetryDispatcher]; + MSIDTelemetry.sharedInstance.piiEnabled = piiEnabled; +} + +- (BOOL)notifyOnFailureOnly +{ + return MSIDTelemetry.sharedInstance.notifyOnFailureOnly; } -- (void)removeDispatcher:(id)dispatcher +- (void)setNotifyOnFailureOnly:(BOOL)notifyOnFailureOnly { - [MSIDTelemetry.sharedInstance findAndRemoveDispatcher:dispatcher]; + MSIDTelemetry.sharedInstance.notifyOnFailureOnly = notifyOnFailureOnly; } -- (void)removeAllDispatchers +#pragma mark - Private + +- (void)initDispatchers { - [MSIDTelemetry.sharedInstance removeAllDispatchers]; + __auto_type aggregatedProxyObserver = [MSALTelemetryEventsObservingProxy new]; + aggregatedProxyObserver.telemetryCallback = ^(NSDictionary *event) + { + if (self.telemetryCallback != nil) self.telemetryCallback(event); + }; + __auto_type aggregatedDispatcher = [[MSIDAggregatedDispatcher alloc] initWithObserver:aggregatedProxyObserver]; + + [[MSIDTelemetry sharedInstance] addDispatcher:aggregatedDispatcher]; } @end diff --git a/MSAL/src/configuration/external/MSALExternalAccountHandler.h b/MSAL/src/configuration/external/MSALExternalAccountHandler.h new file mode 100644 index 0000000000..6ce50e83c5 --- /dev/null +++ b/MSAL/src/configuration/external/MSALExternalAccountHandler.h @@ -0,0 +1,50 @@ +// 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 + +@protocol MSALExternalAccountProviding; +@class MSALResult; +@class MSALAccount; +@protocol MSALExternalAccount; +@class MSALAccountEnumerationParameters; +@class MSALOauth2Provider; + +NS_ASSUME_NONNULL_BEGIN + +@interface MSALExternalAccountHandler : NSObject + +@property (nonatomic, nonnull, readonly) NSArray> *externalAccountProviders; +@property (nonatomic, nonnull, readonly) MSALOauth2Provider *oauth2Provider; + +- (nullable instancetype)initWithExternalAccountProviders:(NSArray> *)externalAccountProviders + oauth2Provider:(MSALOauth2Provider *)oauth2Provider + error:(NSError * _Nullable * _Nullable)error; + +- (BOOL)updateWithResult:(MSALResult *)result error:(NSError * _Nullable * _Nullable)error; +- (BOOL)removeAccount:(MSALAccount *)account error:(NSError * _Nullable * _Nullable)error; +- (nullable NSArray *)allExternalAccountsWithParameters:(MSALAccountEnumerationParameters *)parameters error:(NSError * _Nullable * _Nullable)error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/src/configuration/external/MSALExternalAccountHandler.m b/MSAL/src/configuration/external/MSALExternalAccountHandler.m new file mode 100644 index 0000000000..27af4de29d --- /dev/null +++ b/MSAL/src/configuration/external/MSALExternalAccountHandler.m @@ -0,0 +1,183 @@ +// 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 "MSALExternalAccountHandler.h" +#import "MSALExternalAccountProviding.h" +#import "MSALTenantProfile.h" +#import "MSALAccount.h" +#import "MSALAADAuthority.h" +#import "MSALResult.h" +#import "MSALAccount+MultiTenantAccount.h" +#import "MSALOauth2Provider.h" +#import "MSALAccount+Internal.h" +#import "MSALErrorConverter.h" +#import "MSALResult.h" +#import "MSALTenantProfile.h" + +@interface MSALExternalAccountHandler() + +@property (nonatomic, nonnull, readwrite) NSArray> *externalAccountProviders; +@property (nonatomic, nonnull, readwrite) MSALOauth2Provider *oauth2Provider; + +@end + +@implementation MSALExternalAccountHandler + +#pragma mark - Init + +- (instancetype)initWithExternalAccountProviders:(NSArray> *)externalAccountProviders + oauth2Provider:(MSALOauth2Provider *)oauth2Provider + error:(NSError **)error +{ + if (![externalAccountProviders count]) + { + MSID_LOG_WITH_CTX(MSIDLogLevelVerbose, nil, @"No external account providers found"); + return nil; + } + + if (!oauth2Provider) + { + [self fillAndLogParameterError:error parameterName:@"oauth2Provider"]; + return nil; + } + + self = [super init]; + + if (self) + { + _externalAccountProviders = externalAccountProviders; + _oauth2Provider = oauth2Provider; + } + + return self; +} + +#pragma mark - Accounts + +- (BOOL)removeAccount:(MSALAccount *)account error:(NSError **)error +{ + if (!account) + { + [self fillAndLogParameterError:error parameterName:@"account"]; + return NO; + } + + for (id provider in self.externalAccountProviders) + { + NSError *removalError = nil; + BOOL result = [provider removeAccount:account tenantProfiles:account.tenantProfiles error:&removalError]; + + if (!result) + { + MSID_LOG_WITH_CTX_PII(MSIDLogLevelWarning, nil, @"Failed to remove external account with error %@", MSID_PII_LOG_MASKABLE(removalError)); + + if (error) + { + *error = [MSALErrorConverter msalErrorFromMsidError:removalError]; + } + + return NO; + } + } + + return YES; +} + +- (BOOL)updateWithResult:(MSALResult *)result error:(NSError **)error +{ + if (!result) + { + [self fillAndLogParameterError:error parameterName:@"result"]; + return NO; + } + + NSError *updateError = nil; + MSALAccount *copiedAccount = [result.account copy]; + + for (id provider in self.externalAccountProviders) + { + BOOL updateResult = [provider updateAccount:copiedAccount idTokenClaims:result.tenantProfile.claims error:&updateError]; + + if (!updateResult) + { + MSID_LOG_WITH_CTX_PII(MSIDLogLevelWarning, nil, @"Failed to update account with error %@", MSID_PII_LOG_MASKABLE(updateError)); + + if (error) + { + *error = [MSALErrorConverter msalErrorFromMsidError:updateError]; + } + + return NO; + } + } + + return YES; +} + +- (NSArray *)allExternalAccountsWithParameters:(MSALAccountEnumerationParameters *)parameters error:(NSError **)error +{ + NSMutableArray *allExternalAccounts = [NSMutableArray new]; + + for (id provider in self.externalAccountProviders) + { + NSError *externalError = nil; + NSArray *externalAccounts = [provider accountsWithParameters:parameters error:&externalError]; + + if (externalError) + { + MSID_LOG_WITH_CTX_PII(MSIDLogLevelWarning, nil, @"Failed to read external accounts with parameters %@ with error %@", MSID_PII_LOG_MASKABLE(parameters), MSID_PII_LOG_MASKABLE(externalError)); + + if (error) *error = [MSALErrorConverter msalErrorFromMsidError:externalError]; + return nil; + } + + for (id externalAccount in externalAccounts) + { + MSALAccount *msalAccount = [[MSALAccount alloc] initWithMSALExternalAccount:externalAccount oauth2Provider:self.oauth2Provider]; + + if (msalAccount) + { + [allExternalAccounts addObject:msalAccount]; + } + } + } + + return allExternalAccounts; +} + +#pragma mark - Helpers + +- (void)fillAndLogParameterError:(NSError **)error parameterName:(NSString *)parameterName +{ + NSString *errorMessage = [NSString stringWithFormat:@"Parameter missing: %@", parameterName]; + MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"%@", errorMessage); + + if (error) + { + NSError *msidError = MSIDCreateError(MSIDErrorDomain, MSIDErrorInternal, errorMessage, nil, nil, nil, nil, nil); + NSError *msalError = [MSALErrorConverter msalErrorFromMsidError:msidError]; + *error = msalError; + } +} + +@end diff --git a/MSAL/src/telemetry/MSALTelemetryDefaultEvent.m b/MSAL/src/configuration/external/MSALSerializedADALCacheProvider+Internal.h similarity index 78% rename from MSAL/src/telemetry/MSALTelemetryDefaultEvent.m rename to MSAL/src/configuration/external/MSALSerializedADALCacheProvider+Internal.h index db342503d8..b719bf439a 100644 --- a/MSAL/src/telemetry/MSALTelemetryDefaultEvent.m +++ b/MSAL/src/configuration/external/MSALSerializedADALCacheProvider+Internal.h @@ -21,21 +21,16 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#import "MSALTelemetryDefaultEvent.h" +#import +#import "MSALSerializedADALCacheProvider.h" +#import "MSIDTokenCacheDataSource.h" -@implementation MSALTelemetryDefaultEvent +NS_ASSUME_NONNULL_BEGIN -- (id)initWithName:(NSString *)eventName - context:(id)context -{ - if (!(self = [super initWithName:eventName context:context])) - { - return nil; - } - - [self addDefaultProperties]; - - return self; -} +@interface MSALSerializedADALCacheProvider (Internal) + +- (id)msidTokenCacheDataSource; @end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/src/configuration/external/MSALSerializedADALCacheProvider.m b/MSAL/src/configuration/external/MSALSerializedADALCacheProvider.m new file mode 100644 index 0000000000..2200b608d7 --- /dev/null +++ b/MSAL/src/configuration/external/MSALSerializedADALCacheProvider.m @@ -0,0 +1,103 @@ +// 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 "MSALSerializedADALCacheProvider.h" +#import "MSIDMacTokenCache.h" +#import "MSALErrorConverter.h" +#import "MSALSerializedADALCacheProvider+Internal.h" + +@interface MSALSerializedADALCacheProvider() + +@property (nonatomic, nonnull, readwrite) id delegate; +@property (nonatomic, readwrite) MSIDMacTokenCache *macTokenCache; + +@end + +@implementation MSALSerializedADALCacheProvider + +- (instancetype)initWithDelegate:(id)delegate + error:(NSError **)error +{ + self = [super init]; + + if (self) + { + _delegate = delegate; + + // Init datasource. + _macTokenCache = [MSIDMacTokenCache new]; + _macTokenCache.delegate = self; + } + + return self; +} + +- (nullable NSData *)serializeDataWithError:(NSError **)error +{ + // TODO: error. + return [self.macTokenCache serialize]; +} + +- (BOOL)deserialize:(nonnull NSData *)serializedData error:(NSError **)error +{ + return [self.macTokenCache deserialize:serializedData error:error]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + MSALSerializedADALCacheProvider *copiedCacheProvider = [[MSALSerializedADALCacheProvider alloc] initWithDelegate:self.delegate error:nil]; + return copiedCacheProvider; +} + +#pragma mark - Internal + +- (id)msidTokenCacheDataSource +{ + return self.macTokenCache; +} + +#pragma mark - MSIDMacTokenCacheDelegate + +- (void)willAccessCache:(MSIDMacTokenCache *)cache +{ + [self.delegate willAccessCache:self]; +} + +- (void)didAccessCache:(MSIDMacTokenCache *)cache +{ + [self.delegate didAccessCache:self]; +} + +- (void)willWriteCache:(MSIDMacTokenCache *)cache +{ + [self.delegate willWriteCache:self]; +} + +- (void)didWriteCache:(MSIDMacTokenCache *)cache +{ + [self.delegate didWriteCache:self]; +} + +@end diff --git a/MSAL/src/configuration/external/ios/MSALLegacySharedADALAccount.h b/MSAL/src/configuration/external/ios/MSALLegacySharedADALAccount.h new file mode 100644 index 0000000000..e0785a3d1d --- /dev/null +++ b/MSAL/src/configuration/external/ios/MSALLegacySharedADALAccount.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 +#import "MSALAccount.h" +#import "MSALLegacySharedAccount.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MSALLegacySharedADALAccount : MSALLegacySharedAccount + +@end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/src/configuration/external/ios/MSALLegacySharedADALAccount.m b/MSAL/src/configuration/external/ios/MSALLegacySharedADALAccount.m new file mode 100644 index 0000000000..16e53c3ff7 --- /dev/null +++ b/MSAL/src/configuration/external/ios/MSALLegacySharedADALAccount.m @@ -0,0 +1,175 @@ +// 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 "MSALLegacySharedADALAccount.h" +#import "MSIDAADAuthority.h" +#import "MSIDJsonObject.h" +#import "NSDictionary+MSIDExtensions.h" +#import "MSIDAccountIdentifier.h" +#import "MSALAccountEnumerationParameters.h" +#import "MSALAADAuthority.h" + +static NSString *kADALAccountType = @"ADAL"; + +@interface MSALLegacySharedADALAccount() + +@property (nonatomic) MSIDAADAuthority *authority; +@property (nonatomic) NSString *objectId; +@property (nonatomic) NSString *tenantId; +@property (nonatomic, readwrite) NSString *environment; +@property (nonatomic, readwrite) NSString *identifier; +@property (nonatomic, readwrite) NSDictionary *accountClaims; + +@end + +@implementation MSALLegacySharedADALAccount + +#pragma mark - Init + +- (instancetype)initWithJSONDictionary:(NSDictionary *)jsonDictionary error:(NSError **)error +{ + self = [super initWithJSONDictionary:jsonDictionary error:error]; + + if (self) + { + MSID_LOG_WITH_CTX(MSIDLogLevelInfo, nil, @"Creating external account from ADAL account"); + + if (![_accountType isEqualToString:kADALAccountType]) + { + MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"Failed to create ADAL account. Wrong account type %@ provided", _accountType); + + if (error) + { + *error = MSIDCreateError(MSIDErrorDomain, MSIDErrorInternal, @"Unexpected account type", nil, nil, nil, nil, nil); + } + + return nil; + } + + NSString *authEndpoint = [jsonDictionary msidStringObjectForKey:@"authEndpointUrl"]; + + if (!authEndpoint) + { + MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"Failed to read AAD authority. Nil authority provided"); + + if (error) + { + *error = MSIDCreateError(MSIDErrorDomain, MSIDErrorInternal, @"Unexpected authority found", nil, nil, nil, nil, nil); + } + + return nil; + } + + _authority = [[MSIDAADAuthority alloc] initWithURL:[NSURL URLWithString:authEndpoint] rawTenant:nil context:nil error:error]; + + if (!_authority) + { + MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"Failed to create AAD authority. Wrong authority provided %@", authEndpoint); + return nil; + } + + _environment = [_authority cacheEnvironmentWithContext:nil]; + + _objectId = [jsonDictionary msidStringObjectForKey:@"oid"]; + _tenantId = [jsonDictionary msidStringObjectForKey:@"tenantId"]; + + if (_authority.tenant.type == MSIDAADTenantTypeCommon) + { + _identifier = [MSIDAccountIdentifier homeAccountIdentifierFromUid:_objectId utid:_tenantId]; + } + + NSMutableDictionary *claims = [NSMutableDictionary new]; + + if (![NSString msidIsStringNilOrBlank:_objectId]) + { + claims[@"oid"] = _objectId; + } + + if (![NSString msidIsStringNilOrBlank:_tenantId]) + { + claims[@"tid"] = _tenantId; + } + + NSString *displayName = [jsonDictionary msidStringObjectForKey:@"displayName"]; + + if (![NSString msidIsStringNilOrBlank:displayName]) + { + claims[@"name"] = displayName; + } + + _username = [jsonDictionary msidStringObjectForKey:@"username"]; + _accountClaims = claims; + + MSID_LOG_WITH_CTX_PII(MSIDLogLevelInfo, nil, @"Created external ADAL account with identifier %@, object Id %@, tenant Id %@, name %@, username %@, claims %@", MSID_PII_LOG_TRACKABLE(_identifier), MSID_PII_LOG_MASKABLE(_objectId), _tenantId, MSID_PII_LOG_MASKABLE(displayName), MSID_PII_LOG_EMAIL(_username), MSID_PII_LOG_MASKABLE(_accountClaims)); + } + + return self; +} + +#pragma mark - Match + +- (BOOL)matchesParameters:(MSALAccountEnumerationParameters *)parameters +{ + BOOL matchResult = YES; + + if (parameters.identifier) + { + matchResult &= ([self.identifier caseInsensitiveCompare:parameters.identifier] == NSOrderedSame); + } + + if (parameters.username) + { + matchResult &= ([self.username caseInsensitiveCompare:parameters.username] == NSOrderedSame); + } + + if (parameters.tenantProfileIdentifier) + { + matchResult &= ([self.objectId caseInsensitiveCompare:parameters.tenantProfileIdentifier] == NSOrderedSame); + } + + return matchResult &= [super matchesParameters:parameters]; +} + +#pragma mark - Updates + +- (NSDictionary *)claimsFromMSALAccount:(id)account claims:(NSDictionary *)claims +{ + NSMutableDictionary *jsonDictionary = [NSMutableDictionary new]; + jsonDictionary[@"displayName"] = claims[@"name"]; + jsonDictionary[@"oid"] = claims[@"oid"]; + jsonDictionary[@"tenantId"] = claims[@"tid"]; + jsonDictionary[@"username"] = account.username; + jsonDictionary[@"type"] = @"ADAL"; + + MSIDAccountIdentifier *accountIdentifier = [[MSIDAccountIdentifier alloc] initWithDisplayableId:nil homeAccountId:account.identifier]; + BOOL isHomeTenant = [accountIdentifier.utid isEqualToString:claims[@"tid"]]; + + MSALAADAuthority *aadAuthority = [[MSALAADAuthority alloc] initWithEnvironment:account.environment + audienceType:isHomeTenant ? MSALAzureADAndPersonalMicrosoftAccountAudience : MSALAzureADMyOrgOnlyAudience + rawTenant:isHomeTenant ? nil : claims[@"tid"] + error:nil]; + jsonDictionary[@"authEndpointUrl"] = aadAuthority.url.absoluteString; + return jsonDictionary; +} + +@end diff --git a/MSAL/src/configuration/external/ios/MSALLegacySharedAccount.h b/MSAL/src/configuration/external/ios/MSALLegacySharedAccount.h new file mode 100644 index 0000000000..a3c9c415d3 --- /dev/null +++ b/MSAL/src/configuration/external/ios/MSALLegacySharedAccount.h @@ -0,0 +1,84 @@ +// 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 + +@class MSIDJsonObject; +@class MSALAccountEnumerationParameters; +@protocol MSALAccount; + +// Every time there's a new field added, version update is required +// Versions are identified numerically (V1, V2, V3) +typedef NS_ENUM(NSInteger, MSALLegacySharedAccountVersion) +{ + MSALLegacySharedAccountVersionV1 = 1, + MSALLegacySharedAccountVersionV2, + MSALLegacySharedAccountVersionV3 +}; + +typedef NS_ENUM(NSInteger, MSALLegacySharedAccountWriteOperation) +{ + MSALLegacySharedAccountRemoveOperation = 0, + MSALLegacySharedAccountUpdateOperation +}; + +NS_ASSUME_NONNULL_BEGIN + +@interface MSALLegacySharedAccount : NSObject +{ + NSString *_username; + NSString *_accountType; +} + +@property (nonatomic, readonly) NSDictionary *jsonDictionary; +@property (nonatomic, readonly) NSString *accountType; +@property (nonatomic, readonly) NSString *accountIdentifier; +@property (nonatomic, readonly) NSDictionary *signinStatusDictionary; +@property (nonatomic, readonly) NSString *username; + +- (nullable instancetype)initWithJSONDictionary:(NSDictionary *)jsonDictionary error:(NSError * _Nullable * _Nullable)error; +- (BOOL)matchesParameters:(MSALAccountEnumerationParameters *)parameters; + +/* + Updates existing account with MSAL account fields. + Not thread safe. + */ +- (BOOL)updateAccountWithMSALAccount:(id)account + applicationName:(NSString *)appName + operation:(MSALLegacySharedAccountWriteOperation)operation + accountVersion:(MSALLegacySharedAccountVersion)accountVersion + error:(NSError * _Nullable * _Nullable)error; + + +/* + Creates new account based on MSAL account. + */ +- (nullable instancetype)initWithMSALAccount:(id)account + accountClaims:(NSDictionary *)claims + applicationName:(NSString *)appName + accountVersion:(MSALLegacySharedAccountVersion)accountVersion + error:(NSError * _Nullable * _Nullable)error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/src/configuration/external/ios/MSALLegacySharedAccount.m b/MSAL/src/configuration/external/ios/MSALLegacySharedAccount.m new file mode 100644 index 0000000000..681278de00 --- /dev/null +++ b/MSAL/src/configuration/external/ios/MSALLegacySharedAccount.m @@ -0,0 +1,206 @@ +// 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 "MSALLegacySharedAccount.h" +#import "MSIDJsonObject.h" +#import "NSDictionary+MSIDExtensions.h" +#import "MSALAccountEnumerationParameters.h" +#import + +@interface MSALLegacySharedAccount() + +@property (nonatomic, readwrite) NSDictionary *jsonDictionary; +@property (nonatomic, readwrite) NSString *username; + +@end + +static NSDateFormatter *s_updateDateFormatter = nil; + +@implementation MSALLegacySharedAccount + +#pragma mark - Init + +- (instancetype)initWithJSONDictionary:(NSDictionary *)jsonDictionary error:(NSError **)error +{ + self = [super init]; + + if (self) + { + _jsonDictionary = jsonDictionary; + _accountType = [jsonDictionary msidStringObjectForKey:@"type"]; + _accountIdentifier = [jsonDictionary msidStringObjectForKey:@"id"]; + + if ([NSString msidIsStringNilOrBlank:_accountType] + || [NSString msidIsStringNilOrBlank:_accountIdentifier]) + { + MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"Missing account type or identifier (account type = %@, account identifier = %@)", _accountType, _accountIdentifier); + + if (error) + { + *error = MSIDCreateError(MSIDErrorDomain, MSIDErrorInternal, @"Unexpected shared account found without type or identifier", nil, nil, nil, nil, nil); + } + + return nil; + } + + _signinStatusDictionary = [jsonDictionary msidObjectForKey:@"signInStatus" ofClass:[NSDictionary class]]; + MSID_LOG_WITH_CTX_PII(MSIDLogLevelInfo, nil, @"Created sign in status dictionary %@", MSID_PII_LOG_MASKABLE(_signinStatusDictionary)); + } + + return self; +} + +- (instancetype)initWithMSALAccount:(id)account + accountClaims:(NSDictionary *)claims + applicationName:(NSString *)appName + accountVersion:(MSALLegacySharedAccountVersion)accountVersion + error:(NSError **)error +{ + if (accountVersion == MSALLegacySharedAccountVersionV1) + { + return nil; + } + + if (!account) + { + if (error) + { + *error = MSIDCreateError(MSIDErrorDomain, MSIDErrorInternal, @"Unexpected parameter - no account", nil, nil, nil, nil, nil); + } + + return nil; + } + + NSString *appBundleId = [[NSBundle mainBundle] bundleIdentifier]; + + NSMutableDictionary *jsonDictionary = [NSMutableDictionary new]; + jsonDictionary[@"id"] = [[NSUUID UUID] UUIDString]; + jsonDictionary[@"environment"] = @"PROD"; + + if (accountVersion == MSALLegacySharedAccountVersionV3) + { + jsonDictionary[@"originAppId"] = appBundleId; + } + + jsonDictionary[@"signInStatus"] = @{appBundleId : @"SignedIn"}; + jsonDictionary[@"username"] = account.username; + jsonDictionary[@"additionalProperties"] = @{@"createdBy": appName}; + [jsonDictionary addEntriesFromDictionary:[self claimsFromMSALAccount:account claims:claims]]; + return [self initWithJSONDictionary:jsonDictionary error:error]; +} + +#pragma mark - Match + +- (BOOL)matchesParameters:(MSALAccountEnumerationParameters *)parameters +{ + if (parameters.returnOnlySignedInAccounts) + { + NSString *appIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + NSString *signinStatus = [self.signinStatusDictionary msidStringObjectForKey:appIdentifier]; + + if (![signinStatus isEqualToString:@"SignedIn"]) + { + return NO; + } + } + + return YES; +} + +#pragma mark - Update + +- (BOOL)updateAccountWithMSALAccount:(id)account + applicationName:(NSString *)appName + operation:(MSALLegacySharedAccountWriteOperation)operation + accountVersion:(MSALLegacySharedAccountVersion)accountVersion + error:(NSError **)error +{ + if (accountVersion == MSALLegacySharedAccountVersionV1) + { + return YES; + } + + NSMutableDictionary *oldDictionary = [self.jsonDictionary mutableCopy]; + NSString *appIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + + if (appIdentifier) + { + NSMutableDictionary *signinDictionary = [NSMutableDictionary new]; + [signinDictionary addEntriesFromDictionary:self.signinStatusDictionary]; + + NSString *signinState = nil; + + switch (operation) { + case MSALLegacySharedAccountRemoveOperation: + signinState = @"SignedOut"; + break; + case MSALLegacySharedAccountUpdateOperation: + signinState = @"SignedIn"; + break; + + default: + return NO; + } + + signinDictionary[appIdentifier] = signinState; + oldDictionary[@"signInStatus"] = signinDictionary; + } + + NSDictionary *additionalAccountInfo = [self.jsonDictionary msidObjectForKey:@"additionalProperties" ofClass:[NSDictionary class]]; + NSMutableDictionary *mutableAdditionalInfo = [NSMutableDictionary new]; + [mutableAdditionalInfo addEntriesFromDictionary:additionalAccountInfo]; + + mutableAdditionalInfo[@"updatedBy"] = appName; + mutableAdditionalInfo[@"updatedAt"] = [[[self class] dateFormatter] stringFromDate:[NSDate date]]; + + oldDictionary[@"additionalProperties"] = mutableAdditionalInfo; + + if (account.username) + { + self.username = account.username; + oldDictionary[@"username"] = self.username; + } + + self.jsonDictionary = oldDictionary; + return YES; +} + +- (NSDictionary *)claimsFromMSALAccount:(id)account claims:(NSDictionary *)claims +{ + return nil; +} + +#pragma mark - Helpers + ++ (NSDateFormatter *)dateFormatter +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + s_updateDateFormatter = [NSDateFormatter new]; + [s_updateDateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZ"]; + }); + + return s_updateDateFormatter; +} + +@end diff --git a/MSAL/src/configuration/external/ios/MSALLegacySharedAccountFactory.h b/MSAL/src/configuration/external/ios/MSALLegacySharedAccountFactory.h new file mode 100644 index 0000000000..626b5f2ba4 --- /dev/null +++ b/MSAL/src/configuration/external/ios/MSALLegacySharedAccountFactory.h @@ -0,0 +1,46 @@ +// 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 "MSALLegacySharedAccount.h" + +@class MSIDJsonObject; +@class MSALAccount; +@class MSALAccountEnumerationParameters; +@class MSALTenantProfile; + +@interface MSALLegacySharedAccountFactory : NSObject + ++ (nullable MSALLegacySharedAccount *)accountWithJSONDictionary:(nonnull NSDictionary *)jsonDictionary + error:(NSError * _Nullable * _Nullable)error; + ++ (nullable MSALLegacySharedAccount *)accountWithMSALAccount:(nonnull id)account + claims:(nonnull NSDictionary *)claims + applicationName:(nonnull NSString *)applicationName + accountVersion:(MSALLegacySharedAccountVersion)accountVersion + error:(NSError * _Nullable * _Nullable )error; + ++ (nullable MSALAccountEnumerationParameters *)parametersForAccount:(nonnull id)account + tenantProfileIdentifier:(nullable NSString *)tenantProfileIdentifier; + +@end diff --git a/MSAL/src/configuration/external/ios/MSALLegacySharedAccountFactory.m b/MSAL/src/configuration/external/ios/MSALLegacySharedAccountFactory.m new file mode 100644 index 0000000000..d2ab98bc1c --- /dev/null +++ b/MSAL/src/configuration/external/ios/MSALLegacySharedAccountFactory.m @@ -0,0 +1,118 @@ +// 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 "MSALLegacySharedAccountFactory.h" +#import "MSIDJsonObject.h" +#import "NSDictionary+MSIDExtensions.h" +#import "MSALLegacySharedADALAccount.h" +#import "MSALLegacySharedMSAAccount.h" +#import "MSIDConstants.h" +#import "MSIDAccountIdentifier.h" +#import + +@implementation MSALLegacySharedAccountFactory + ++ (MSALLegacySharedAccount *)accountWithJSONDictionary:(NSDictionary *)jsonDictionary error:(NSError **)error +{ + NSString *accountType = [jsonDictionary msidStringObjectForKey:@"type"]; + + if ([accountType isEqualToString:@"ADAL"]) + { + MSID_LOG_WITH_CTX(MSIDLogLevelInfo, nil, @"Initializing ADAL account type"); + return [[MSALLegacySharedADALAccount alloc] initWithJSONDictionary:jsonDictionary error:error]; + } + else if ([accountType isEqualToString:@"MSA"]) + { + MSID_LOG_WITH_CTX(MSIDLogLevelInfo, nil, @"Initializing MSA account type"); + return [[MSALLegacySharedMSAAccount alloc] initWithJSONDictionary:jsonDictionary error:error]; + } + + if (error) + { + *error = MSIDCreateError(MSIDErrorDomain, MSIDErrorInternal, @"Unexpected account type found", nil, nil, nil, nil, nil); + } + + MSID_LOG_WITH_CTX(MSIDLogLevelInfo, nil, @"Unknown account type found %@", accountType); + return nil; +} + ++ (nullable MSALLegacySharedAccount *)accountWithMSALAccount:(nonnull id)account + claims:(nonnull NSDictionary *)claims + applicationName:(nonnull NSString *)applicationName + accountVersion:(MSALLegacySharedAccountVersion)accountVersion + error:(NSError * _Nullable * _Nullable )error +{ + if ([self isMSAAccount:account]) + { + MSID_LOG_WITH_CTX(MSIDLogLevelInfo, nil, @"Initializing MSA account type"); + return [[MSALLegacySharedMSAAccount alloc] initWithMSALAccount:account + accountClaims:claims + applicationName:applicationName + accountVersion:accountVersion + error:error]; + } + else if (![NSString msidIsStringNilOrBlank:claims[@"oid"]]) + { + MSID_LOG_WITH_CTX(MSIDLogLevelInfo, nil, @"Initializing AAD account type"); + return [[MSALLegacySharedADALAccount alloc] initWithMSALAccount:account + accountClaims:claims + applicationName:applicationName + accountVersion:accountVersion + error:error]; + } + + return nil; +} + ++ (MSALAccountEnumerationParameters *)parametersForAccount:(nonnull id)account + tenantProfileIdentifier:(nullable NSString *)tenantProfileIdentifier +{ + if ([self isMSAAccount:account]) + { + MSALAccountEnumerationParameters *parameters = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:account.identifier]; + parameters.returnOnlySignedInAccounts = NO; + return parameters; + } + else if (![NSString msidIsStringNilOrBlank:tenantProfileIdentifier]) + { + MSALAccountEnumerationParameters *parameters = [[MSALAccountEnumerationParameters alloc] initWithTenantProfileIdentifier:tenantProfileIdentifier]; + parameters.returnOnlySignedInAccounts = NO; + return parameters; + } + + return nil; +} + ++ (BOOL)isMSAAccount:(id)account +{ + MSIDAccountIdentifier *accountIdentifier = [[MSIDAccountIdentifier alloc] initWithDisplayableId:nil homeAccountId:account.identifier]; + + if (accountIdentifier.utid && [accountIdentifier.utid isEqualToString:MSID_DEFAULT_MSA_TENANTID]) + { + return YES; + } + + return NO; +} + +@end diff --git a/MSAL/src/configuration/external/ios/MSALLegacySharedAccountsProvider.m b/MSAL/src/configuration/external/ios/MSALLegacySharedAccountsProvider.m new file mode 100644 index 0000000000..222cac4a21 --- /dev/null +++ b/MSAL/src/configuration/external/ios/MSALLegacySharedAccountsProvider.m @@ -0,0 +1,540 @@ +// 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 "MSALLegacySharedAccountsProvider.h" +#import "MSIDKeychainTokenCache.h" +#import "MSIDCacheKey.h" +#import "MSIDCacheItemJsonSerializer.h" +#import "MSALLegacySharedAccountFactory.h" +#import "MSIDJsonObject.h" +#import "MSALLegacySharedAccount.h" +#import "MSALAccountEnumerationParameters.h" +#import "MSIDConstants.h" +#import "MSALErrorConverter.h" +#import "MSALAccount.h" +#import "MSALTenantProfile.h" + +@interface MSALLegacySharedAccountsProvider() + +@property (nonatomic) MSIDKeychainTokenCache *keychainTokenCache; +@property (nonatomic) NSString *serviceIdentifier; +@property (nonatomic) NSString *applicationIdentifier; +@property (nonatomic) dispatch_queue_t synchronizationQueue; + +@end + +@implementation MSALLegacySharedAccountsProvider + +#pragma mark - Init + +- (instancetype)initWithSharedKeychainAccessGroup:(NSString *)sharedGroup + serviceIdentifier:(NSString *)serviceIdentifier + applicationIdentifier:(NSString *)applicationIdentifier +{ + self = [super init]; + + if (self) + { + self.keychainTokenCache = [[MSIDKeychainTokenCache alloc] initWithGroup:sharedGroup]; + self.serviceIdentifier = serviceIdentifier; + self.applicationIdentifier = applicationIdentifier; + + NSString *queueName = [NSString stringWithFormat:@"com.microsoft.legacysharedaccountsprovider-%@", [NSUUID UUID].UUIDString]; + _synchronizationQueue = dispatch_queue_create([queueName cStringUsingEncoding:NSASCIIStringEncoding], DISPATCH_QUEUE_CONCURRENT); + } + + return self; +} + +#pragma mark - MSALExternalAccountProviding +#pragma mark - Read + +- (nullable NSArray> *)accountsWithParameters:(MSALAccountEnumerationParameters *)parameters + error:(NSError * _Nullable * _Nullable)error +{ + __block NSArray *results = nil; + __block NSError *readError = nil; + + dispatch_sync(self.synchronizationQueue, ^{ + results = [self accountsWithParametersImpl:parameters error:&readError]; + }); + + if (error && readError) + { + *error = readError; + } + + return results; +} + +- (nullable NSArray> *)accountsWithParametersImpl:(MSALAccountEnumerationParameters *)parameters + error:(NSError * _Nullable * _Nullable)error +{ + MSID_LOG_WITH_CTX_PII(MSIDLogLevelInfo, nil, @"Reading accounts with parameters %@", MSID_PII_LOG_MASKABLE(parameters)); + + NSMutableSet *allAccounts = [NSMutableSet new]; + NSTimeInterval lastWrite = [[NSDate distantPast] timeIntervalSince1970]; + + for (int version = MSALLegacySharedAccountVersionV3; version >= MSALLegacySharedAccountVersionV1; version--) + { + NSString *versionIdentifier = [self accountVersionIdentifier:version]; + NSError *readError = nil; + MSIDJsonObject *jsonObject = [self jsonObjectWithVersion:version error:&readError]; + + if (!jsonObject) + { + if (readError) + { + NSString *logLine = [NSString stringWithFormat:@"Failed to retrieve accounts with version %@", versionIdentifier]; + [self fillAndLogError:error withError:readError logLine:logLine]; + return nil; + } + + continue; + } + + NSDictionary *jsonDictionary = [jsonObject jsonDictionary]; + NSNumber *lastWriteForVersion = [jsonDictionary msidObjectForKey:@"lastWriteTimestamp" ofClass:[NSNumber class]]; + + MSID_LOG_WITH_CTX_PII(MSIDLogLevelInfo, nil, @"Reading accounts with version %@, last write time stamp %@", versionIdentifier, lastWriteForVersion); + + if ([lastWriteForVersion floatValue] > lastWrite) + { + MSID_LOG_WITH_CTX_PII(MSIDLogLevelInfo, nil, @"Accounts with version %@ are latest", versionIdentifier); + + NSArray *accounts = [self accountsFromJsonObject:jsonDictionary withParameters:parameters error:&readError]; + + if (!accounts) + { + [self fillAndLogError:error withError:readError logLine:@"Failed to deserialize accounts"]; + return nil; + } + + lastWrite = [lastWriteForVersion floatValue]; + [allAccounts addObjectsFromArray:accounts]; + } + else + { + MSID_LOG_WITH_CTX(MSIDLogLevelInfo, nil, @"Older accounts dictionary found with version %@, skipping...", versionIdentifier); + break; + } + } + + NSArray *results = [allAccounts allObjects]; + MSID_LOG_WITH_CTX_PII(MSIDLogLevelVerbose, nil, @"Finished reading external accounts with results %@", MSID_PII_LOG_MASKABLE(results)); + return results; +} + +- (nullable NSArray *)accountsFromJsonObject:(NSDictionary *)jsonDictionary + withParameters:(MSALAccountEnumerationParameters *)parameters + error:(NSError **)error +{ + NSMutableArray *resultAccounts = [NSMutableArray new]; + + for (NSString *accountId in [jsonDictionary allKeys]) + { + NSDictionary *singleAccountDictionary = [jsonDictionary msidObjectForKey:accountId ofClass:[NSDictionary class]]; + + if (!singleAccountDictionary) + { + continue; + } + + NSError *singleAccountError = nil; + MSALLegacySharedAccount *account = [MSALLegacySharedAccountFactory accountWithJSONDictionary:singleAccountDictionary error:&singleAccountError]; + + if (!account) + { + MSID_LOG_WITH_CTX_PII(MSIDLogLevelWarning, nil, @"Failed to create account with error %@", MSID_PII_LOG_MASKABLE(singleAccountError)); + continue; + } + + if ([account matchesParameters:parameters]) + { + [resultAccounts addObject:account]; + } + } + + return resultAccounts; +} + +#pragma mark - Update + +- (BOOL)updateAccount:(id)account idTokenClaims:(NSDictionary *)idTokenClaims error:(NSError **)error +{ + MSID_LOG_WITH_CTX_PII(MSIDLogLevelInfo, nil, @"Updating account %@", MSID_PII_LOG_MASKABLE(account)); + + return [self updateAccount:account + idTokenClaims:idTokenClaims + tenantProfiles:nil + operation:MSALLegacySharedAccountUpdateOperation + error:error]; +} + +- (nullable NSArray *)updatableAccountsFromJsonObject:(NSDictionary *)jsonDictionary + msalAccount:(id)msalAccount + idTokenClaims:(NSDictionary *)idTokenClaims + version:(MSALLegacySharedAccountVersion)version + error:(NSError **)error +{ + MSALAccountEnumerationParameters *parameters = [MSALLegacySharedAccountFactory parametersForAccount:msalAccount tenantProfileIdentifier:idTokenClaims[@"oid"]]; + + if (!parameters) + { + NSError *parameterError = MSIDCreateError(MSIDErrorDomain, MSIDErrorInternal, @"Unsupported account found, skipping update", nil, nil, nil, nil, nil); + [self fillAndLogError:error withError:parameterError logLine:@"Unsupported account found, skipping update"]; + return nil; + } + + NSError *parseError = nil; + NSArray *accounts = [self accountsFromJsonObject:jsonDictionary withParameters:parameters error:&parseError]; + + if (parseError) + { + [self fillAndLogError:error withError:parseError logLine:@"Failed to parse accounts"]; + return nil; + } + + if (![accounts count]) + { + NSError *accountError = nil; + MSALLegacySharedAccount *sharedAccount = [MSALLegacySharedAccountFactory accountWithMSALAccount:msalAccount + claims:idTokenClaims + applicationName:self.applicationIdentifier + accountVersion:version + error:&accountError]; + if (!sharedAccount) + { + if (accountError) + { + [self fillAndLogError:error withError:accountError logLine:@"Failed to create account"]; + return nil; + } + + return @[]; + } + + accounts = @[sharedAccount]; + } + + return accounts; +} + +#pragma mark - Removal + +- (BOOL)removeAccount:(id)account + tenantProfiles:(nullable NSArray *)tenantProfiles + error:(NSError * _Nullable * _Nullable)error +{ + MSID_LOG_WITH_CTX_PII(MSIDLogLevelInfo, nil, @"Removing account %@", MSID_PII_LOG_MASKABLE(account)); + return [self updateAccount:account + idTokenClaims:nil + tenantProfiles:tenantProfiles + operation:MSALLegacySharedAccountRemoveOperation + error:error]; +} + +- (nullable NSArray *)removableAccountsFromJsonObject:(NSDictionary *)jsonDictionary + msalAccount:(id)account + tenantProfiles:(NSArray *)tenantProfiles + error:(NSError **)error +{ + if (![tenantProfiles count]) + { + MSALAccountEnumerationParameters *parameters = [MSALLegacySharedAccountFactory parametersForAccount:account + tenantProfileIdentifier:account.accountClaims[@"oid"]]; + + if (!parameters) + { + NSError *parameterError = MSIDCreateError(MSIDErrorDomain, MSIDErrorInternal, @"Unable to create parameters for the account", nil, nil, nil, nil, nil); + [self fillAndLogError:error withError:parameterError logLine:@"Failed to create parameters for the account"]; + return nil; + } + + return [self accountsFromJsonObject:jsonDictionary withParameters:parameters error:error]; + } + + NSMutableArray *allAccounts = [NSMutableArray new]; + + for (MSALTenantProfile *tenantProfile in tenantProfiles) + { + MSALAccountEnumerationParameters *parameters = [MSALLegacySharedAccountFactory parametersForAccount:account + tenantProfileIdentifier:tenantProfile.identifier]; + + if (!parameters) + { + NSError *parameterError = MSIDCreateError(MSIDErrorDomain, MSIDErrorInternal, @"Unable to create parameters for the account", nil, nil, nil, nil, nil); + [self fillAndLogError:error withError:parameterError logLine:@"Failed to create parameters for the account"]; + return nil; + } + + NSArray *accounts = [self accountsFromJsonObject:jsonDictionary withParameters:parameters error:error]; + + if (!accounts) + { + return nil; + } + + [allAccounts addObjectsFromArray:accounts]; + } + + return allAccounts; +} + +#pragma mark - Write + +- (BOOL)updateAccount:(id)account + idTokenClaims:(NSDictionary *)idTokenClaims + tenantProfiles:(NSArray *)tenantProfiles + operation:(MSALLegacySharedAccountWriteOperation)operation + error:(NSError **)error +{ + __block BOOL result = YES; + __block NSError *updateError = nil; + + dispatch_barrier_sync(self.synchronizationQueue, ^{ + result = [self updateAccountImpl:account + idTokenClaims:idTokenClaims + tenantProfiles:tenantProfiles + operation:operation + error:&updateError]; + }); + + if (error && updateError) + { + *error = updateError; + } + + return result; +} + +- (BOOL)updateAccountImpl:(id)account + idTokenClaims:(NSDictionary *)idTokenClaims + tenantProfiles:(NSArray *)tenantProfiles + operation:(MSALLegacySharedAccountWriteOperation)operation + error:(NSError **)error +{ + if (self.sharedAccountMode != MSALLegacySharedAccountModeReadWrite) + { + return YES; + } + + NSTimeInterval writeTimeStamp = [[NSDate date] timeIntervalSince1970]; + + for (int version = MSALLegacySharedAccountVersionV1; version <= MSALLegacySharedAccountVersionV3; version++) + { + NSString *versionIdentifier = [self accountVersionIdentifier:version]; + MSID_LOG_WITH_CTX(MSIDLogLevelInfo, nil, @"Updating accounts with version %@", versionIdentifier); + + NSError *updateError = nil; + MSIDJsonObject *jsonObject = [self jsonObjectWithVersion:version error:&updateError]; + + if (updateError) + { + NSString *logLine = [NSString stringWithFormat:@"Failed to retrieve accounts with version %@", versionIdentifier]; + [self fillAndLogError:error withError:updateError logLine:logLine]; + return NO; + } + + NSArray *accounts = nil; + + if (operation == MSALLegacySharedAccountRemoveOperation) + { + accounts = [self removableAccountsFromJsonObject:[jsonObject jsonDictionary] + msalAccount:account + tenantProfiles:tenantProfiles + error:&updateError]; + } + else + { + accounts = [self updatableAccountsFromJsonObject:[jsonObject jsonDictionary] + msalAccount:account + idTokenClaims:idTokenClaims + version:version + error:&updateError]; + } + + if (!accounts) + { + NSString *logLine = [NSString stringWithFormat:@"Failed to parse accounts with version %@", versionIdentifier]; + [self fillAndLogError:error withError:updateError logLine:logLine]; + return NO; + } + + MSID_LOG_WITH_CTX(MSIDLogLevelInfo, nil, @"Updating accounts %@", MSID_PII_LOG_MASKABLE(accounts)); + + NSError *saveError = nil; + BOOL saveResult = [self saveUpdatedAccount:account + jsonObject:jsonObject + accounts:accounts + operation:operation + version:version + writeTime:writeTimeStamp + error:&saveError]; + + if (!saveResult) + { + [self fillAndLogError:error withError:saveError logLine:@"Failed to save accounts"]; + return NO; + } + + writeTimeStamp += 1.0; + } + + return YES; +} + +- (BOOL)saveUpdatedAccount:(id)account + jsonObject:(MSIDJsonObject *)jsonObject + accounts:(NSArray *)accounts + operation:(MSALLegacySharedAccountWriteOperation)operation + version:(MSALLegacySharedAccountVersion)version + writeTime:(NSTimeInterval)writeTimeStamp + error:(NSError **)error +{ + NSString *versionIdentifier = [self accountVersionIdentifier:version]; + NSMutableDictionary *resultDictionary = jsonObject ? [[jsonObject jsonDictionary] mutableCopy] : [NSMutableDictionary new]; + + MSID_LOG_WITH_CTX(MSIDLogLevelInfo, nil, @"Updating accounts %@", MSID_PII_LOG_MASKABLE(accounts)); + + for (MSALLegacySharedAccount *sharedAccount in accounts) + { + NSError *updateError = nil; + BOOL updateResult = [sharedAccount updateAccountWithMSALAccount:account + applicationName:self.applicationIdentifier + operation:operation + accountVersion:version + error:&updateError]; + + if (!updateResult) + { + NSString *logLine = [NSString stringWithFormat:@"Failed to update accounts with version %@", versionIdentifier]; + [self fillAndLogError:error withError:updateError logLine:logLine]; + return NO; + } + + resultDictionary[sharedAccount.accountIdentifier] = [sharedAccount jsonDictionary]; + } + + resultDictionary[@"lastWriteTimestamp"] = @((long)writeTimeStamp); + + NSError *saveError = nil; + BOOL saveResult = [self saveJSONDictionary:resultDictionary + version:version + error:&saveError]; + + if (!saveResult) + { + [self fillAndLogError:error withError:saveError logLine:@"Failed to save accounts"]; + return NO; + } + + return YES; +} + +#pragma mark - Keychain operations + +- (nullable MSIDJsonObject *)jsonObjectWithVersion:(MSALLegacySharedAccountVersion)version + error:(NSError **)error +{ + NSString *versionIdentifier = [self accountVersionIdentifier:version]; + MSIDCacheKey *cacheKey = [[MSIDCacheKey alloc] initWithAccount:versionIdentifier + service:self.serviceIdentifier + generic:nil + type:nil]; + + NSError *readError = nil; + NSArray *jsonAccounts = [self.keychainTokenCache jsonObjectsWithKey:cacheKey + serializer:[MSIDCacheItemJsonSerializer new] + context:nil + error:&readError]; + + if (![jsonAccounts count]) + { + if (readError) + { + NSString *logLine = [NSString stringWithFormat:@"Failed to read external accounts with version %@", versionIdentifier]; + [self fillAndLogError:error withError:readError logLine:logLine]; + } + + return nil; + } + + if ([jsonAccounts count] > 1) + { + NSError *readError = MSIDCreateError(MSIDErrorDomain, MSIDErrorInternal, @"Ambigious query for external accounts, found multiple accounts.", nil, nil, nil, nil, nil); + [self fillAndLogError:error withError:readError logLine:@"Ambigious query for external accounts, found multiple accounts."]; + return nil; + } + + return jsonAccounts[0]; +} + +- (BOOL)saveJSONDictionary:(NSDictionary *)jsonDictionary + version:(MSALLegacySharedAccountVersion)version + error:(NSError **)error +{ + NSString *versionIdentifier = [self accountVersionIdentifier:version]; + MSID_LOG_WITH_CTX(MSIDLogLevelInfo, nil, @"Saving accounts with version %@", versionIdentifier); + + MSIDCacheKey *cacheKey = [[MSIDCacheKey alloc] initWithAccount:versionIdentifier + service:self.serviceIdentifier + generic:nil + type:nil]; + + NSError *saveError = nil; + MSIDJsonObject *jsonObject = [[MSIDJsonObject alloc] initWithJSONDictionary:jsonDictionary error:&saveError]; + BOOL saveResult = [self.keychainTokenCache saveJsonObject:jsonObject + serializer:[MSIDCacheItemJsonSerializer new] + key:cacheKey + context:nil + error:&saveError]; + + if (!saveResult) + { + NSString *logLine = [NSString stringWithFormat:@"Failed to save accounts with version %@", versionIdentifier]; + [self fillAndLogError:error withError:saveError logLine:logLine]; + return NO; + } + + return YES; +} + +#pragma mark - Helpers + +- (void)fillAndLogError:(NSError **)error withError:(NSError *)resultError logLine:(NSString *)logLine +{ + MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"%@, error %@", logLine, MSID_PII_LOG_MASKABLE(resultError)); + + if (error && resultError) + { + *error = [MSALErrorConverter msalErrorFromMsidError:resultError]; + } +} + +- (NSString *)accountVersionIdentifier:(MSALLegacySharedAccountVersion)version +{ + return [NSString stringWithFormat:@"AccountsV%d", (int)version]; +} + +@end diff --git a/MSAL/src/telemetry/MSALTelemetryDefaultEvent.h b/MSAL/src/configuration/external/ios/MSALLegacySharedMSAAccount.h similarity index 84% rename from MSAL/src/telemetry/MSALTelemetryDefaultEvent.h rename to MSAL/src/configuration/external/ios/MSALLegacySharedMSAAccount.h index 972bafc916..c52add902a 100644 --- a/MSAL/src/telemetry/MSALTelemetryDefaultEvent.h +++ b/MSAL/src/configuration/external/ios/MSALLegacySharedMSAAccount.h @@ -21,8 +21,14 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#import "MSIDTelemetryBaseEvent.h" +#import +#import "MSALLegacySharedAccount.h" +#import "MSALAccount.h" -@interface MSALTelemetryDefaultEvent : MSIDTelemetryBaseEvent +NS_ASSUME_NONNULL_BEGIN + +@interface MSALLegacySharedMSAAccount : MSALLegacySharedAccount @end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/src/configuration/external/ios/MSALLegacySharedMSAAccount.m b/MSAL/src/configuration/external/ios/MSALLegacySharedMSAAccount.m new file mode 100644 index 0000000000..3679d1275e --- /dev/null +++ b/MSAL/src/configuration/external/ios/MSALLegacySharedMSAAccount.m @@ -0,0 +1,142 @@ +// 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 "MSALLegacySharedMSAAccount.h" +#import "MSIDJsonObject.h" +#import "MSIDAADAuthority.h" +#import "MSIDConstants.h" +#import "MSIDAccountIdentifier.h" +#import "NSString+MSALAccountIdenfiers.h" +#import "MSALAccountEnumerationParameters.h" + +static NSString *kMSAAccountType = @"MSA"; + +@interface MSALLegacySharedMSAAccount() + +@property (nonatomic) MSIDAADAuthority *authority; +@property (nonatomic, readwrite) NSString *environment; +@property (nonatomic, readwrite) NSString *identifier; +@property (nonatomic, readwrite) NSDictionary *accountClaims; + +@end + +static NSString *kDefaultCacheAuthority = @"https://login.windows.net/common"; + +@implementation MSALLegacySharedMSAAccount + +#pragma mark - Init + +- (instancetype)initWithJSONDictionary:(NSDictionary *)jsonDictionary error:(NSError **)error +{ + self = [super initWithJSONDictionary:jsonDictionary error:error]; + + if (self) + { + if (![_accountType isEqualToString:kMSAAccountType]) + { + if (error) + { + *error = MSIDCreateError(MSIDErrorDomain, MSIDErrorInternal, @"Unexpected account type", nil, nil, nil, nil, nil); + } + + return nil; + } + + _authority = [[MSIDAADAuthority alloc] initWithURL:[NSURL URLWithString:kDefaultCacheAuthority] rawTenant:nil context:nil error:error]; + + _environment = [_authority cacheEnvironmentWithContext:nil]; + // cid == hash of PUID (Live account ID) + NSString *cid = [jsonDictionary msidStringObjectForKey:@"cid"]; + NSString *uid = [cid msalStringAsGUID]; + + if ([NSString msidIsStringNilOrBlank:uid]) + { + MSID_LOG_WITH_CTX_PII(MSIDLogLevelError, nil, @"Unable to read cid from MSA account, cid %@", cid); + + if (error) + { + *error = MSIDCreateError(MSIDErrorDomain, MSIDErrorInternal, @"Unexpected identifier found for MSA account", nil, nil, nil, nil, nil); + } + + return nil; + } + + _identifier = [MSIDAccountIdentifier homeAccountIdentifierFromUid:uid utid:MSID_DEFAULT_MSA_TENANTID]; + _username = [jsonDictionary msidStringObjectForKey:@"email"]; + + _accountClaims = @{@"tid": MSID_DEFAULT_MSA_TENANTID, + @"oid": uid}; + + MSID_LOG_WITH_CTX_PII(MSIDLogLevelInfo, nil, @"Created external MSA account with identifier %@, object Id %@, tenant Id %@, username %@, claims %@", MSID_PII_LOG_TRACKABLE(_identifier), MSID_PII_LOG_MASKABLE(cid), MSID_DEFAULT_MSA_TENANTID, MSID_PII_LOG_EMAIL(_username), MSID_PII_LOG_MASKABLE(_accountClaims)); + } + + return self; +} + +- (instancetype)initWithMSALAccount:(id)account + accountClaims:(NSDictionary *)claims + applicationName:(NSString *)appName + accountVersion:(MSALLegacySharedAccountVersion)accountVersion + error:(NSError **)error +{ + return nil; // Creating new MSA accounts isn't supported currently and will be added at a later point +} + +#pragma mark - Match + +- (BOOL)matchesParameters:(MSALAccountEnumerationParameters *)parameters +{ + BOOL matchResult = YES; + + if (parameters.identifier) + { + matchResult &= ([self.identifier caseInsensitiveCompare:parameters.identifier] == NSOrderedSame); + } + + if (parameters.username) + { + matchResult &= ([self.username caseInsensitiveCompare:parameters.username] == NSOrderedSame); + } + + if (parameters.tenantProfileIdentifier) + { + return NO; + } + + return matchResult &= [super matchesParameters:parameters]; +} + +#pragma mark - Updates + +- (NSDictionary *)claimsFromMSALAccount:(id)account claims:(NSDictionary *)claims +{ + NSMutableDictionary *jsonDictionary = [NSMutableDictionary new]; + jsonDictionary[@"displayName"] = claims[@"name"] ? claims[@"name"] : account.username; + MSIDAccountIdentifier *accountIdentifier = [[MSIDAccountIdentifier alloc] initWithDisplayableId:nil homeAccountId:account.identifier]; + jsonDictionary[@"cid"] = [accountIdentifier.uid msalGUIDAsShortString]; + jsonDictionary[@"email"] = account.username; + jsonDictionary[@"type"] = @"MSA"; + return jsonDictionary; +} + +@end diff --git a/MSAL/src/telemetry/MSALDefaultDispatcher.h b/MSAL/src/configuration/external/ios/NSString+MSALAccountIdenfiers.h similarity index 71% rename from MSAL/src/telemetry/MSALDefaultDispatcher.h rename to MSAL/src/configuration/external/ios/NSString+MSALAccountIdenfiers.h index 1afa470d80..0dad048fe0 100644 --- a/MSAL/src/telemetry/MSALDefaultDispatcher.h +++ b/MSAL/src/configuration/external/ios/NSString+MSALAccountIdenfiers.h @@ -21,15 +21,16 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#import "MSIDTelemetryDispatcher.h" -#import "MSALTelemetryConfig.h" +#import -@interface MSALDefaultDispatcher : NSObject +NS_ASSUME_NONNULL_BEGIN -+ (instancetype)new __attribute__((unavailable("new is unavailable, use initWithDispatcher instead."))); -- (instancetype)init __attribute__((unavailable("init is unavailable, use initWithDispatcher instead."))); +@interface NSString (MSALAccountIdenfiers) -- (id)initWithDispatcher:(id)dispatcher - setTelemetryOnFailure:(BOOL)setTelemetryOnFailure; +- (NSString *)msalStringAsGUID; +- (NSData *)msalStringAsGUIDData; +- (NSString *)msalGUIDAsShortString; @end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/src/configuration/external/ios/NSString+MSALAccountIdenfiers.m b/MSAL/src/configuration/external/ios/NSString+MSALAccountIdenfiers.m new file mode 100644 index 0000000000..54bc542d2d --- /dev/null +++ b/MSAL/src/configuration/external/ios/NSString+MSALAccountIdenfiers.m @@ -0,0 +1,116 @@ +// 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 "NSString+MSALAccountIdenfiers.h" +#import "NSString+MSIDExtensions.h" + +@implementation NSString (MSALAccountIdenfiers) + +- (NSString *)msalStringAsGUID +{ + if (self.length != 16) + { + MSID_LOG_WITH_CTX(MSIDLogLevelWarning, nil, @"Unexpected string lenght"); + return nil; + } + + NSData *guidData = [self msalStringAsGUIDData]; + + if (!guidData) + { + return nil; + } + + NSUUID *uuid = [[NSUUID alloc] initWithUUIDBytes:[guidData bytes]]; + return uuid.UUIDString.lowercaseString; +} + +- (NSData *)msalStringAsGUIDData +{ + int stringLen = (int)[self length]; + + if (stringLen > 16) + { + return nil; + } + + NSUInteger zeroFillLen = (16 - (stringLen + 1) / 2); + NSMutableData *result = [[NSMutableData alloc] initWithLength:16]; + + char chars[3] = {'\0','\0','\0'}; + + for (int i = stringLen-1; i >= 0; i-=2) + { + unsigned char firstChar = '0'; + + if (i - 1 >= 0) + { + firstChar = [self characterAtIndex:i-1]; + } + + unsigned char secondChar = [self characterAtIndex:i]; + + chars[0] = firstChar; + chars[1] = secondChar; + unsigned char resultChar = strtol(chars, NULL, 16); + + [result replaceBytesInRange:NSMakeRange(zeroFillLen+i/2, 1) withBytes:&resultChar]; + } + + return result; +} + +- (NSString *)msalGUIDAsShortString +{ + NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:self]; + + if (!uuid) + { + return nil; + } + + uuid_t uuidBytes; + [uuid getUUIDBytes:uuidBytes]; + + NSUInteger dataLength = 16; + NSMutableString *result = [NSMutableString stringWithCapacity:dataLength*2]; + + BOOL ignoreLeadingZeroes = YES; + for (NSUInteger i = 0; i < dataLength; i++) + { + if (!ignoreLeadingZeroes || uuidBytes[i] != 0) + { + NSString *format = ignoreLeadingZeroes ? @"%x" : @"%02x"; + [result appendFormat:format, uuidBytes[i]]; + } + + if (uuidBytes[i] != 0) + { + ignoreLeadingZeroes = NO; + } + } + + return result; +} + +@end diff --git a/MSAL/src/instance/MSALAADAuthority.m b/MSAL/src/instance/MSALAADAuthority.m index ceb85f0a31..3e495bb5b5 100644 --- a/MSAL/src/instance/MSALAADAuthority.m +++ b/MSAL/src/instance/MSALAADAuthority.m @@ -28,6 +28,8 @@ #import "MSALAADAuthority.h" #import "MSALAuthority_Internal.h" #import "MSIDAADAuthority.h" +#import "MSALErrorConverter.h" +#import "NSURL+MSIDAADUtils.h" @implementation MSALAADAuthority @@ -51,6 +53,130 @@ - (nullable instancetype)initWithURL:(nonnull NSURL *)url return self; } +- (instancetype)initWithCloudInstance:(MSALAzureCloudInstance)cloudInstance + audienceType:(MSALAudienceType)audienceType + rawTenant:(NSString *)rawTenant + error:(NSError **)error +{ + NSString *environment = [self environmentFromCloudInstance:cloudInstance]; + + if (!environment) + { + if (error) + { + NSError *msidError = MSIDCreateError(MSIDErrorDomain, MSIDErrorInvalidDeveloperParameter, @"Invalid MSALAzureCloudInstance provided", nil, nil, nil, nil, nil); + *error = [MSALErrorConverter msalErrorFromMsidError:msidError]; + } + + return nil; + } + + return [self initWithEnvironment:environment + audienceType:audienceType + rawTenant:rawTenant + error:error]; +} + +- (instancetype)initWithEnvironment:(NSString *)environment + audienceType:(MSALAudienceType)audienceType + rawTenant:(NSString *)rawTenant + error:(NSError **)error +{ + if ([NSString msidIsStringNilOrBlank:environment]) + { + if (error) + { + NSError *msidError = MSIDCreateError(MSIDErrorDomain, MSIDErrorInvalidDeveloperParameter, @"Invalid environment provided", nil, nil, nil, nil, nil); + *error = [MSALErrorConverter msalErrorFromMsidError:msidError]; + } + + return nil; + } + + if (![NSString msidIsStringNilOrBlank:rawTenant]) + { + if (audienceType != MSALAzureADMyOrgOnlyAudience) + { + if (error) + { + NSError *msidError = MSIDCreateError(MSIDErrorDomain, MSIDErrorInvalidDeveloperParameter, @"Invalid MSALAudienceType provided. You can only provide rawTenant when using MSALAzureADMyOrgOnlyAudience.", nil, nil, nil, nil, nil); + *error = [MSALErrorConverter msalErrorFromMsidError:msidError]; + } + + return nil; + } + + NSURL *aadURL = [NSURL msidAADURLWithEnvironment:environment tenant:rawTenant]; + return [self initWithURL:aadURL rawTenant:nil error:error]; + } + + NSString *audienceString = [self audienceFromType:audienceType error:error]; + + if (!audienceString) + { + return nil; + } + + NSURL *aadURL = [NSURL msidAADURLWithEnvironment:environment tenant:audienceString]; + return [self initWithURL:aadURL rawTenant:nil error:error]; +} + +// https://docs.microsoft.com/en-us/azure/active-directory/develop/authentication-national-cloud#azure-ad-authentication-endpoints +- (NSString *)environmentFromCloudInstance:(MSALAzureCloudInstance)cloudInstance +{ + switch (cloudInstance) { + case MSALAzurePublicCloudInstance: + return @"login.microsoftonline.com"; + case MSALAzureChinaCloudInstance: + return @"login.chinacloudapi.cn"; + case MSALAzureGermanyCloudInstance: + return @"login.microsoftonline.de"; + case MSALAzureUsGovernmentCloudInstance: + return @"login.microsoftonline.us"; + + default: + return nil; + } +} + +- (NSString *)audienceFromType:(MSALAudienceType)audienceType error:(NSError **)error +{ + NSError *msidError = nil; + + switch (audienceType) { + case MSALAzureADAndPersonalMicrosoftAccountAudience: + { + return @"common"; + } + case MSALAzureADMultipleOrgsAudience: + { + return @"organizations"; + } + case MSALAzureADMyOrgOnlyAudience: + { + msidError = MSIDCreateError(MSIDErrorDomain, MSIDErrorInvalidDeveloperParameter, @"Invalid MSALAudienceType provided. You must provide rawTenant when using MSALAzureADMyOrgOnlyAudience.", nil, nil, nil, nil, nil);; + break; + } + case MSALPersonalMicrosoftAccountAudience: + { + return @"consumers"; + } + + default: + { + msidError = MSIDCreateError(MSIDErrorDomain, MSIDErrorInvalidDeveloperParameter, @"Invalid MSALAudienceType provided. You must provide rawTenant when using MSALAzureADMyOrgOnlyAudience.", nil, nil, nil, nil, nil); + break; + } + } + + if (msidError && error) + { + *error = [MSALErrorConverter msalErrorFromMsidError:msidError]; + } + + return nil; +} + - (NSURL *)url { return self.msidAuthority.url; diff --git a/MSAL/src/instance/MSALADFSAuthority.m b/MSAL/src/instance/MSALADFSAuthority.m index 5536b03a3e..eb3cdae5d9 100644 --- a/MSAL/src/instance/MSALADFSAuthority.m +++ b/MSAL/src/instance/MSALADFSAuthority.m @@ -30,12 +30,23 @@ #import "MSIDADFSAuthority.h" #import "MSIDAuthority+Internal.h" #import "MSALAuthority_Internal.h" +#import "MSALErrorConverter.h" @implementation MSALADFSAuthority +#define ADFS_NOT_YET_SUPPORTED + - (instancetype)initWithURL:(NSURL *)url error:(NSError **)error { +#ifdef ADFS_NOT_YET_SUPPORTED + if (error) + { + NSError *msidError = MSIDCreateError(MSIDErrorDomain, MSIDErrorUnsupportedFunctionality, @"AD FS authority is not supported yet in MSAL", nil, nil, nil, nil, nil); + *error = [MSALErrorConverter msalErrorFromMsidError:msidError]; + } + return nil; +#else self = [super initWithURL:url error:error]; if (self) { @@ -44,6 +55,7 @@ - (instancetype)initWithURL:(NSURL *)url } return self; +#endif } - (NSURL *)url diff --git a/MSAL/src/instance/MSALAccountsProvider.h b/MSAL/src/instance/MSALAccountsProvider.h index bd2e5498ab..32fbb24e71 100644 --- a/MSAL/src/instance/MSALAccountsProvider.h +++ b/MSAL/src/instance/MSALAccountsProvider.h @@ -30,21 +30,35 @@ @class MSALAccount; @class MSIDDefaultTokenCacheAccessor; @class MSALAuthority; +@class MSIDAccount; +@class MSIDIdTokenClaims; +@class MSALExternalAccountHandler; +@class MSALAccountEnumerationParameters; @interface MSALAccountsProvider : NSObject +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + - (instancetype)initWithTokenCache:(MSIDDefaultTokenCacheAccessor *)tokenCache clientId:(NSString *)clientId; +- (instancetype)initWithTokenCache:(MSIDDefaultTokenCacheAccessor *)tokenCache + clientId:(NSString *)clientId + externalAccountProvider:(MSALExternalAccountHandler *)externalAccountProvider NS_DESIGNATED_INITIALIZER; + +// Authority filtering (deprecated) - (void)allAccountsFilteredByAuthority:(MSALAuthority *)authority completionBlock:(MSALAccountsCompletionBlock)completionBlock; +// Convinience - (NSArray *)allAccounts:(NSError * __autoreleasing *)error; -- (MSALAccount *)accountForHomeAccountId:(NSString *)homeAccountId - error:(NSError * __autoreleasing *)error; +- (MSALAccount *)accountForParameters:(MSALAccountEnumerationParameters *)parameters + error:(NSError * __autoreleasing *)error; -- (MSALAccount *)accountForUsername:(NSString *)username - error:(NSError * __autoreleasing *)error; +// Filtering +- (NSArray *)accountsForParameters:(MSALAccountEnumerationParameters *)parameters + error:(NSError * __autoreleasing *)error; @end diff --git a/MSAL/src/instance/MSALAccountsProvider.m b/MSAL/src/instance/MSALAccountsProvider.m index 4a37a445b5..c43f22c3cc 100644 --- a/MSAL/src/instance/MSALAccountsProvider.m +++ b/MSAL/src/instance/MSALAccountsProvider.m @@ -37,11 +37,23 @@ #import "MSIDConfiguration.h" #import "MSIDAppMetadataCacheItem.h" #import "MSIDConstants.h" +#import "MSIDAADAuthority.h" +#import "MSIDB2CAuthority.h" +#import "MSIDADFSAuthority.h" +#import "MSIDIdTokenClaims.h" +#import "MSALAccount+Internal.h" +#import "MSIDIdToken.h" +#import "MSALExternalAccountHandler.h" +#import "MSALAccountEnumerationParameters.h" +#import "MSALErrorConverter.h" +#import "MSALTenantProfile.h" @interface MSALAccountsProvider() @property (nullable, nonatomic) MSIDDefaultTokenCacheAccessor *tokenCache; @property (nullable, nonatomic) NSString *clientId; +@property (nullable, nonatomic) MSALExternalAccountHandler *externalAccountProvider; +@property (nullable, nonatomic) NSPredicate *homeTenantFilterPredicate; @end @@ -51,6 +63,15 @@ @implementation MSALAccountsProvider - (instancetype)initWithTokenCache:(MSIDDefaultTokenCacheAccessor *)tokenCache clientId:(NSString *)clientId +{ + return [self initWithTokenCache:tokenCache + clientId:clientId + externalAccountProvider:nil]; +} + +- (instancetype)initWithTokenCache:(MSIDDefaultTokenCacheAccessor *)tokenCache + clientId:(NSString *)clientId + externalAccountProvider:(MSALExternalAccountHandler *)externalAccountProvider { self = [super init]; @@ -58,141 +79,212 @@ - (instancetype)initWithTokenCache:(MSIDDefaultTokenCacheAccessor *)tokenCache { _tokenCache = tokenCache; _clientId = clientId; + _externalAccountProvider = externalAccountProvider; + _homeTenantFilterPredicate = [NSPredicate predicateWithFormat:@"isHomeTenantProfile == YES"]; } return self; } -#pragma mark - Accounts +#pragma mark - Convenience -- (void)allAccountsFilteredByAuthority:(MSALAuthority *)authority - completionBlock:(MSALAccountsCompletionBlock)completionBlock; +- (NSArray *)allAccounts:(NSError * __autoreleasing *)error { - [authority.msidAuthority resolveAndValidate:NO - userPrincipalName:nil - context:nil - completionBlock:^(NSURL * _Nullable openIdConfigurationEndpoint, BOOL validated, NSError * _Nullable error) { - - if (error) - { - completionBlock(nil, error); - return; - } - - NSError *accountsError = nil; - NSArray *accounts = [self allAccountsForAuthority:authority.msidAuthority error:&accountsError]; - completionBlock(accounts, accountsError); - }]; + return [self accountsForParameters:[MSALAccountEnumerationParameters new] authority:nil error:error]; } -#pragma mark - Accounts sync - -- (NSArray *)allAccounts:(NSError * __autoreleasing *)error +- (NSArray *)accountsForParameters:(MSALAccountEnumerationParameters *)parameters + error:(NSError * __autoreleasing *)error { - return [self allAccountsForAuthority:nil error:error]; + return [self accountsForParameters:parameters authority:nil error:error]; } -- (MSALAccount *)accountForHomeAccountId:(NSString *)homeAccountId - error:(NSError * __autoreleasing *)error +- (MSALAccount *)accountForParameters:(MSALAccountEnumerationParameters *)parameters + error:(NSError * __autoreleasing *)error { - NSError *msidError = nil; - - MSIDAppMetadataCacheItem *appMetadata = [self appMetadataItem]; - NSString *familyId = appMetadata ? appMetadata.familyId : MSID_DEFAULT_FAMILY_ID; - - MSIDAccountIdentifier *accountIdentifier = [[MSIDAccountIdentifier alloc] initWithDisplayableId:nil homeAccountId:homeAccountId]; - NSArray *msidAccounts = [self.tokenCache accountsWithAuthority:nil - clientId:self.clientId - familyId:familyId - accountIdentifier:accountIdentifier - context:nil - error:&msidError]; + NSError *internalError = nil; + NSArray *accounts = [self accountsForParameters:parameters authority:nil error:&internalError]; - if (msidError) + if (internalError) { - *error = msidError; + if (error) *error = internalError; return nil; } - - if ([msidAccounts count]) + + if ([accounts count]) { - MSALAccount *msalAccount = [[MSALAccount alloc] initWithMSIDAccount:msidAccounts[0]]; - return msalAccount; + if (accounts.count == 1) + { + return accounts[0]; + } + else if (accounts.count > 1) + { + MSID_LOG_WITH_CTX(MSIDLogLevelWarning, nil, @"Retrieved more than 1 msal accounts! (More info: environments are equal for first 2 accounts: %@, homeAccountIds are equal for first 2 accounts: %@, usernames are equal for first 2 accounts: %@)", accounts[0].environment == accounts[1].environment ? @"YES" : @"NO", accounts[0].homeAccountId == accounts[1].homeAccountId ? @"YES" : @"NO", accounts[0].username == accounts[1].username ? @"YES" : @"NO"); + return accounts[0]; + } } - + return nil; } -- (MSALAccount *)accountForUsername:(NSString *)username - error:(NSError * __autoreleasing *)error +#pragma mark - Filtering + +- (NSArray *)accountsForParameters:(MSALAccountEnumerationParameters *)parameters + authority:(MSIDAuthority *)authority + error:(NSError * __autoreleasing *)error { NSError *msidError = nil; - - MSIDAppMetadataCacheItem *appMetadata = [self appMetadataItem]; - NSString *familyId = appMetadata ? appMetadata.familyId : MSID_DEFAULT_FAMILY_ID; - - MSIDAccountIdentifier *accountIdentifier = [[MSIDAccountIdentifier alloc] initWithDisplayableId:username homeAccountId:nil]; - - NSArray *msidAccounts = [self.tokenCache accountsWithAuthority:nil - clientId:self.clientId - familyId:familyId - accountIdentifier:accountIdentifier + + NSString *queryClientId = nil; + NSString *queryFamilyId = nil; + + if (!parameters || parameters.returnOnlySignedInAccounts) + { + MSIDAppMetadataCacheItem *appMetadata = [self appMetadataItem]; + NSString *familyId = appMetadata ? appMetadata.familyId : MSID_DEFAULT_FAMILY_ID; + + queryClientId = self.clientId; + + queryFamilyId = familyId; + } + + MSIDAccountIdentifier *queryAccountIdentifier = nil; + + if (![NSString msidIsStringNilOrBlank:parameters.identifier] + || ![NSString msidIsStringNilOrBlank:parameters.username]) + { + queryAccountIdentifier = [[MSIDAccountIdentifier alloc] initWithDisplayableId:parameters.username homeAccountId:parameters.identifier]; + } + + NSArray *msidAccounts = [self.tokenCache accountsWithAuthority:authority + clientId:queryClientId + familyId:queryFamilyId + accountIdentifier:queryAccountIdentifier context:nil error:&msidError]; if (msidError) { - *error = msidError; + if (error) + { + *error = [MSALErrorConverter msalErrorFromMsidError:msidError]; + } return nil; } - if ([msidAccounts count]) + if (![NSString msidIsStringNilOrBlank:parameters.tenantProfileIdentifier]) { - MSALAccount *msalAccount = [[MSALAccount alloc] initWithMSIDAccount:msidAccounts[0]]; - return msalAccount; + NSMutableArray *filteredAccounts = [NSMutableArray new]; + + for (MSIDAccount *account in msidAccounts) + { + if ([account.localAccountId isEqualToString:parameters.tenantProfileIdentifier]) + { + [filteredAccounts addObject:account.localAccountId]; + } + } + + msidAccounts = filteredAccounts; } - return nil; + NSArray *externalAccounts = nil; + + if (self.externalAccountProvider) + { + NSError *externalError = nil; + externalAccounts = [self.externalAccountProvider allExternalAccountsWithParameters:parameters error:&externalError]; + + if (externalError) + { + MSID_LOG_WITH_CTX_PII(MSIDLogLevelWarning, nil, @"Failed to read accounts from external cache with error %@. Ignoring error...", MSID_PII_LOG_MASKABLE(externalError)); + } + } + + return [self msalAccountsFromMSIDAccounts:msidAccounts externalAccounts:externalAccounts]; } -#pragma mark - Private +#pragma mark - Internal -- (NSArray *)allAccountsForAuthority:(MSIDAuthority *)authority - error:(NSError * __autoreleasing *)error +- (NSArray *)msalAccountsFromMSIDAccounts:(NSArray *)msidAccounts + externalAccounts:(NSArray *)externalAccounts { - NSError *msidError = nil; - - MSIDAppMetadataCacheItem *appMetadata = [self appMetadataItem]; - NSString *familyId = appMetadata ? appMetadata.familyId : MSID_DEFAULT_FAMILY_ID; - - NSArray *msidAccounts = [self.tokenCache accountsWithAuthority:authority - clientId:self.clientId - familyId:familyId - accountIdentifier:nil - context:nil - error:&msidError]; + NSMutableSet *resultAccounts = [NSMutableSet new]; - if (msidError) + for (MSIDAccount *msidAccount in msidAccounts) { - *error = msidError; - return nil; + // if requiresRefreshToken + // make sure account hasn't been marked as removed explicitly + // if it has, don't return it + // also don't flip familyId on account removal anymore + + MSALAccount *msalAccount = [[MSALAccount alloc] initWithMSIDAccount:msidAccount createTenantProfile:YES]; + if (!msalAccount) continue; + + NSDictionary *accountClaims = msidAccount.isHomeTenantAccount ? msidAccount.idTokenClaims.jsonDictionary : nil; + [self addMSALAccount:msalAccount toSet:resultAccounts claims:accountClaims]; } - NSMutableSet *msalAccounts = [NSMutableSet new]; - - for (MSIDAccount *msidAccount in msidAccounts) + for (MSALAccount *externalAccount in externalAccounts) { - MSALAccount *msalAccount = [[MSALAccount alloc] initWithMSIDAccount:msidAccount]; + NSDictionary *accountClaims = nil; - if (msalAccount) + if ([externalAccount.mTenantProfiles count]) { - [msalAccounts addObject:msalAccount]; + NSArray *homeTenantProfileArray = [externalAccount.mTenantProfiles filteredArrayUsingPredicate:self.homeTenantFilterPredicate]; + if ([homeTenantProfileArray count] == 1) accountClaims = homeTenantProfileArray[0].claims; } + + [self addMSALAccount:externalAccount toSet:resultAccounts claims:accountClaims]; } - return [msalAccounts allObjects]; + return [resultAccounts allObjects]; } +- (void)addMSALAccount:(MSALAccount *)account toSet:(NSMutableSet *)allAccountsSet claims:(NSDictionary *)accountClaims +{ + MSALAccount *existingAccount = [allAccountsSet member:account]; + + if (!existingAccount) + { + [allAccountsSet addObject:account]; + existingAccount = account; + } + else + { + [existingAccount addTenantProfiles:account.mTenantProfiles]; + } + + if (accountClaims) + { + existingAccount.accountClaims = accountClaims; + } +} + +#pragma mark - Authority (deprecated) + +- (void)allAccountsFilteredByAuthority:(MSALAuthority *)authority + completionBlock:(MSALAccountsCompletionBlock)completionBlock +{ + [authority.msidAuthority resolveAndValidate:NO + userPrincipalName:nil + context:nil + completionBlock:^(NSURL * _Nullable openIdConfigurationEndpoint, BOOL validated, NSError * _Nullable error) { + + if (error) + { + NSError *msalError = [MSALErrorConverter msalErrorFromMsidError:error]; + completionBlock(nil, msalError); + return; + } + + NSError *accountsError = nil; + NSArray *accounts = [self accountsForParameters:nil authority:authority.msidAuthority error:&accountsError]; + completionBlock(accounts, accountsError); + }]; +} + +#pragma mark - App metadata + - (MSIDAppMetadataCacheItem *)appMetadataItem { MSIDConfiguration *configuration = [[MSIDConfiguration alloc] initWithAuthority:nil redirectUri:nil clientId:self.clientId target:nil]; @@ -202,7 +294,7 @@ - (MSIDAppMetadataCacheItem *)appMetadataItem if (error) { - MSID_LOG_WARN(nil, @"Failed to retrieve app metadata items with error code %ld, %@", (long)error.code, error.domain); + MSID_LOG_WITH_CTX(MSIDLogLevelWarning,nil, @"Failed to retrieve app metadata items with error code %ld, %@", (long)error.code, error.domain); return nil; } diff --git a/MSAL/src/instance/MSALAuthority.m b/MSAL/src/instance/MSALAuthority.m index 5585351184..b2392f8d66 100644 --- a/MSAL/src/instance/MSALAuthority.m +++ b/MSAL/src/instance/MSALAuthority.m @@ -27,7 +27,14 @@ #import "MSALAuthority.h" #import "MSALAuthority_Internal.h" -#import "MSALAuthorityFactory.h" +#import "MSIDB2CAuthority.h" +#import "MSIDADFSAuthority.h" +#import "MSIDAADAuthority.h" +#import "MSALAADAuthority.h" +#import "MSALADFSAuthority.h" +#import "MSALB2CAuthority.h" +#import "MSALOauth2Authority.h" +#import "MSALB2CAuthority_Internal.h" @implementation MSALAuthority @@ -40,9 +47,25 @@ - (instancetype)initWithURL:(nonnull NSURL *)url + (MSALAuthority *)authorityWithURL:(nonnull NSURL *)url error:(NSError * _Nullable __autoreleasing * _Nullable)error { - return [MSALAuthorityFactory authorityFromUrl:url - context:nil - error:error]; + if ([MSIDB2CAuthority isAuthorityFormatValid:url context:nil error:nil]) + { + __auto_type b2cAuthority = [[MSALB2CAuthority alloc] initWithURL:url validateFormat:YES error:nil]; + if (b2cAuthority) return b2cAuthority; + } + + if ([MSIDADFSAuthority isAuthorityFormatValid:url context:nil error:nil]) + { + __auto_type adfsAuthority = [[MSALADFSAuthority alloc] initWithURL:url error:nil]; + if (adfsAuthority) return adfsAuthority; + } + + if ([MSIDAADAuthority isAuthorityFormatValid:url context:nil error:nil]) + { + __auto_type aadAuthority = [[MSALAADAuthority alloc] initWithURL:url rawTenant:nil error:nil]; + if (aadAuthority) return aadAuthority; + } + + return [[MSALOauth2Authority alloc] initWithURL:url error:error]; } #pragma mark - NSCopying diff --git a/MSAL/src/instance/MSALAuthorityFactory.m b/MSAL/src/instance/MSALAuthorityFactory.m deleted file mode 100644 index 5b473acfd9..0000000000 --- a/MSAL/src/instance/MSALAuthorityFactory.m +++ /dev/null @@ -1,75 +0,0 @@ -//------------------------------------------------------------------------------ -// -// 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 "MSALAuthorityFactory.h" -#import "MSALAADAuthority.h" -#import "MSIDAADAuthority.h" -#import "MSALB2CAuthority.h" -#import "MSIDB2CAuthority.h" -#import "MSALADFSAuthority.h" -#import "MSIDADFSAuthority.h" -#import "MSALB2CAuthority_Internal.h" - -@implementation MSALAuthorityFactory - -+ (MSALAuthority *)authorityFromUrl:(NSURL *)url - context:(id)context - error:(NSError **)error -{ - return [self authorityFromUrl:url validateFormat:YES rawTenant:nil context:context error:error]; -} - -+ (MSALAuthority *)authorityFromUrl:(NSURL *)url - validateFormat:(BOOL)validateFormat - rawTenant:(NSString *)rawTenant - context:(id)context - error:(NSError **)error -{ - if ([MSIDB2CAuthority isAuthorityFormatValid:url context:context error:nil]) - { - __auto_type b2cAuthority = [[MSALB2CAuthority alloc] initWithURL:url validateFormat:validateFormat error:nil]; - if (b2cAuthority) return b2cAuthority; - } - - if ([MSIDADFSAuthority isAuthorityFormatValid:url context:context error:nil]) - { - __auto_type adfsAuthority = [[MSALADFSAuthority alloc] initWithURL:url error:nil]; - if (adfsAuthority) return adfsAuthority; - } - - if ([MSIDAADAuthority isAuthorityFormatValid:url context:context error:nil]) - { - __auto_type aadAuthority = [[MSALAADAuthority alloc] initWithURL:url rawTenant:rawTenant error:nil]; - if (aadAuthority) return aadAuthority; - } - - MSIDFillAndLogError(error, MSIDErrorInvalidDeveloperParameter, @"Provided authority url is not a valid authority.", nil); - - return nil; -} - -@end diff --git a/MSAL/test/app/ios/MSALTestAppTelemetryDispatcher.m b/MSAL/src/instance/MSALOauth2Authority.h similarity index 84% rename from MSAL/test/app/ios/MSALTestAppTelemetryDispatcher.m rename to MSAL/src/instance/MSALOauth2Authority.h index df9418708b..60898efe41 100644 --- a/MSAL/test/app/ios/MSALTestAppTelemetryDispatcher.m +++ b/MSAL/src/instance/MSALOauth2Authority.h @@ -25,16 +25,12 @@ // //------------------------------------------------------------------------------ -#import "MSALTestAppTelemetryDispatcher.h" +#import -@implementation MSALTestAppTelemetryDispatcher +NS_ASSUME_NONNULL_BEGIN -- (void)dispatchEvent:(nonnull NSArray *> *)events -{ - if (_dispatcherCallback) - { - _dispatcherCallback(events); - } -} +@interface MSALOauth2Authority : MSALAuthority @end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/src/instance/MSALOauth2Authority.m b/MSAL/src/instance/MSALOauth2Authority.m new file mode 100644 index 0000000000..d2e11a03e8 --- /dev/null +++ b/MSAL/src/instance/MSALOauth2Authority.m @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALOauth2Authority.h" +#import "MSALAuthority_Internal.h" +#import "MSALErrorConverter.h" + +@implementation MSALOauth2Authority + +- (instancetype)initWithURL:(NSURL *)url + error:(NSError **)error +{ + self = [super initWithURL:url error:nil]; + + if (self) + { + if (error) + { + NSError *msidError = MSIDCreateError(MSIDErrorDomain, MSIDErrorUnsupportedFunctionality, @"Non Microsoft authority is not supported yet in MSAL", nil, nil, nil, nil, nil); + *error = [MSALErrorConverter msalErrorFromMsidError:msidError]; + } + } + + return nil; +} + +- (NSURL *)url +{ + return nil; +} + +@end diff --git a/MSAL/src/instance/MSALOauth2FactoryProducer.h b/MSAL/src/instance/MSALOauth2ProviderFactory.h similarity index 63% rename from MSAL/src/instance/MSALOauth2FactoryProducer.h rename to MSAL/src/instance/MSALOauth2ProviderFactory.h index 536be8b674..1c398a78ba 100644 --- a/MSAL/src/instance/MSALOauth2FactoryProducer.h +++ b/MSAL/src/instance/MSALOauth2ProviderFactory.h @@ -27,12 +27,18 @@ #import -@class MSIDOauth2Factory; +@class MSALAuthority; +@class MSALOauth2Provider; +@class MSIDDefaultTokenCacheAccessor; +@class MSIDAccountMetadataCacheAccessor; -@interface MSALOauth2FactoryProducer : NSObject +@interface MSALOauth2ProviderFactory : NSObject -+ (nullable MSIDOauth2Factory *)msidOauth2FactoryForAuthority:(nonnull NSURL *)authority - context:(nullable id)context - error:(NSError * _Nullable __autoreleasing * _Nullable)error; ++ (nullable MSALOauth2Provider *)oauthProviderForAuthority:(nonnull MSALAuthority *)authority + clientId:(nonnull NSString *)clientId + tokenCache:(nullable MSIDDefaultTokenCacheAccessor *)tokenCache + accountMetadataCache:(nullable MSIDAccountMetadataCacheAccessor *)accountMetadataCache + context:(nullable id)context + error:(NSError * _Nullable __autoreleasing * _Nullable)error; @end diff --git a/MSAL/src/instance/MSALOauth2ProviderFactory.m b/MSAL/src/instance/MSALOauth2ProviderFactory.m new file mode 100644 index 0000000000..60e84e9731 --- /dev/null +++ b/MSAL/src/instance/MSALOauth2ProviderFactory.m @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALOauth2ProviderFactory.h" +#import "MSALB2CAuthority.h" +#import "MSALAADAuthority.h" +#import "MSALADFSAuthority.h" +#import "MSALB2COauth2Provider.h" +#import "MSALAADOauth2Provider.h" +#import "MSALADFSAuthority.h" + +@implementation MSALOauth2ProviderFactory + ++ (MSALOauth2Provider *)oauthProviderForAuthority:(MSALAuthority *)authority + clientId:(NSString *)clientId + tokenCache:(MSIDDefaultTokenCacheAccessor *)tokenCache + accountMetadataCache:(MSIDAccountMetadataCacheAccessor *)accountMetadataCache + context:(id)context + error:(NSError **)error +{ + if (!authority) + { + MSIDFillAndLogError(error, MSIDErrorInvalidDeveloperParameter, @"Provided authority url is nil.", nil); + + return nil; + } + + if ([authority isKindOfClass:[MSALB2CAuthority class]]) + { + return [[MSALB2COauth2Provider alloc] initWithClientId:clientId tokenCache:tokenCache accountMetadataCache:accountMetadataCache]; + } + else if ([authority isKindOfClass:[MSALAADAuthority class]]) + { + return [[MSALAADOauth2Provider alloc] initWithClientId:clientId tokenCache:tokenCache accountMetadataCache:accountMetadataCache]; + } + else if ([authority isKindOfClass:[MSALADFSAuthority class]]) + { + MSIDFillAndLogError(error, MSIDErrorUnsupportedFunctionality, @"ADFS authority is not yet supported.", nil); + return nil; + } + + MSIDFillAndLogError(error, MSIDErrorUnsupportedFunctionality, @"Provided authority is not yet supported.", nil); + return nil; + + // In the future, create base factory for everything else, but in future we might want to further separate this out + // (e.g. ADFS, Google, Oauth2 etc...) + // return [MSALOauth2Provider new]; +} + +@end diff --git a/MSAL/test/app/ios/MSALTestAppTelemetryDispatcher.h b/MSAL/src/instance/oauth2/MSALOauth2Provider+Internal.h similarity index 82% rename from MSAL/test/app/ios/MSALTestAppTelemetryDispatcher.h rename to MSAL/src/instance/oauth2/MSALOauth2Provider+Internal.h index 92c326e924..f36806f2f1 100644 --- a/MSAL/test/app/ios/MSALTestAppTelemetryDispatcher.h +++ b/MSAL/src/instance/oauth2/MSALOauth2Provider+Internal.h @@ -25,13 +25,18 @@ // //------------------------------------------------------------------------------ -#import -#import "MSALTelemetry.h" +#import "MSALOauth2Provider.h" -typedef void(^DispatcherCallback)(NSArray *> *events); +@class MSIDOauth2Factory; -@interface MSALTestAppTelemetryDispatcher : NSObject +#ifndef MSALOauth2BaseFactory_Internal_h +#define MSALOauth2BaseFactory_Internal_h -@property (nonatomic, copy) DispatcherCallback dispatcherCallback; +@interface MSALOauth2Provider() + +@property (nonatomic, nonnull, readwrite) MSIDOauth2Factory *msidOauth2Factory; @end + + +#endif /* MSALOauth2BaseFactory_Internal_h */ diff --git a/MSAL/src/instance/oauth2/MSALOauth2Provider.h b/MSAL/src/instance/oauth2/MSALOauth2Provider.h new file mode 100644 index 0000000000..c592ac0fa0 --- /dev/null +++ b/MSAL/src/instance/oauth2/MSALOauth2Provider.h @@ -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 + +NS_ASSUME_NONNULL_BEGIN + +@class MSIDOauth2Factory; +@class MSIDTokenResult; +@class MSIDDefaultTokenCacheAccessor; +@class MSALAccount; +@class MSIDAuthority; +@class MSALTenantProfile; +@class MSALAccountId; +@class MSIDAccountMetadataCacheAccessor; + +@interface MSALOauth2Provider : NSObject + +@property (nonatomic, readonly) MSIDOauth2Factory *msidOauth2Factory; +@property (nonatomic, readonly) NSString *clientId; +@property (nonatomic, readonly) MSIDAccountMetadataCacheAccessor *accountMetadataCache; +@property (nonatomic, readonly) MSIDDefaultTokenCacheAccessor *tokenCache; + +- (nonnull instancetype)init NS_UNAVAILABLE; ++ (nonnull instancetype)new NS_UNAVAILABLE; + +- (instancetype)initWithClientId:(NSString *)clientId + tokenCache:(nullable MSIDDefaultTokenCacheAccessor *)tokenCache + accountMetadataCache:(nullable MSIDAccountMetadataCacheAccessor *)accountMetadataCache; + +- (nullable MSALResult *)resultWithTokenResult:(MSIDTokenResult *)tokenResult + error:(NSError * _Nullable * _Nullable)error; + +- (BOOL)removeAdditionalAccountInfo:(MSALAccount *)account + error:(NSError * _Nullable * _Nullable)error; + +- (MSIDAuthority *)issuerAuthorityWithAccount:(MSALAccount *)account + requestAuthority:(MSIDAuthority *)requestAuthority + instanceAware:(BOOL)instanceAware + error:(NSError **)error; + +- (BOOL)isSupportedAuthority:(MSIDAuthority *)authority; + +- (nullable MSALTenantProfile *)tenantProfileWithClaims:(NSDictionary *)claims + homeAccountId:(MSALAccountId *)homeAccountId + environment:(NSString *)environment + error:(NSError * _Nullable * _Nullable)error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/src/instance/oauth2/MSALOauth2Provider.m b/MSAL/src/instance/oauth2/MSALOauth2Provider.m new file mode 100644 index 0000000000..ad4bb656e1 --- /dev/null +++ b/MSAL/src/instance/oauth2/MSALOauth2Provider.m @@ -0,0 +1,124 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALOauth2Provider.h" +#import "MSIDOauth2Factory.h" +#import "MSIDTokenResult.h" +#import "MSALOauth2Provider+Internal.h" +#import "MSALResult+Internal.h" +#import "MSIDAuthority.h" +#import "MSALAuthority_Internal.h" +#import "MSALOauth2Authority.h" +#import "MSIDIdTokenClaims.h" +#import "MSALTenantProfile+Internal.h" + +@implementation MSALOauth2Provider + +#pragma mark - Public + +- (instancetype)initWithClientId:(NSString *)clientId + tokenCache:(MSIDDefaultTokenCacheAccessor *)tokenCache + accountMetadataCache:(MSIDAccountMetadataCacheAccessor *)accountMetadataCache; + +{ + self = [super init]; + if (self) + { + [self initOauth2Factory]; + _clientId = clientId; + _accountMetadataCache = accountMetadataCache; + _tokenCache = tokenCache; + } + return self; +} + +- (MSALResult *)resultWithTokenResult:(MSIDTokenResult *)tokenResult + error:(NSError **)error +{ + NSError *authorityError = nil; + + MSALAuthority *authority = [[MSALOauth2Authority alloc] initWithURL:tokenResult.authority.url error:error]; + + if (!authority) + { + MSID_LOG_WITH_CTX_PII(MSIDLogLevelWarning, nil, @"Invalid authority, error %@", MSID_PII_LOG_MASKABLE(authorityError)); + + if (error) *error = authorityError; + + return nil; + } + + return [MSALResult resultWithMSIDTokenResult:tokenResult authority:authority error:error]; +} + +- (BOOL)removeAdditionalAccountInfo:(__unused MSALAccount *)account + error:(NSError **)error +{ + return YES; +} + +- (MSIDAuthority *)issuerAuthorityWithAccount:(MSALAccount *)account + requestAuthority:(MSIDAuthority *)requestAuthority + instanceAware:(BOOL)instanceAware + error:(NSError * _Nullable __autoreleasing *)error +{ + // TODO: after authority->issuer cache is ready, this should always lookup cached issuer instead + return requestAuthority; +} + +- (BOOL)isSupportedAuthority:(__unused MSIDAuthority *)authority +{ + return YES; +} + +- (MSALTenantProfile *)tenantProfileWithClaims:(NSDictionary *)claims + homeAccountId:(__unused MSALAccountId *)homeAccountId + environment:(NSString *)environment + error:(NSError **)error +{ + MSIDIdTokenClaims *idTokenClaims = [[MSIDIdTokenClaims alloc] initWithJSONDictionary:claims error:error]; + + if (!idTokenClaims) + { + return nil; + } + + return [[MSALTenantProfile alloc] initWithIdentifier:idTokenClaims.uniqueId + tenantId:idTokenClaims.realm + environment:environment + isHomeTenantProfile:YES + claims:claims]; +} + +#pragma mark - Protected + +- (void)initOauth2Factory +{ + self.msidOauth2Factory = [MSIDOauth2Factory new]; +} + +@end diff --git a/MSAL/test/unit/MSALTelemetryTestDispatcher.h b/MSAL/src/instance/oauth2/aad/MSALAADOauth2Provider.h similarity index 82% rename from MSAL/test/unit/MSALTelemetryTestDispatcher.h rename to MSAL/src/instance/oauth2/aad/MSALAADOauth2Provider.h index e28f91849b..6a4824b8c8 100644 --- a/MSAL/test/unit/MSALTelemetryTestDispatcher.h +++ b/MSAL/src/instance/oauth2/aad/MSALAADOauth2Provider.h @@ -25,13 +25,12 @@ // //------------------------------------------------------------------------------ -#import -#import "MSALTelemetry.h" +#import "MSALOauth2Provider.h" -typedef void(^DispatcherCallback)(NSArray *> *event); +NS_ASSUME_NONNULL_BEGIN -@interface MSALTelemetryTestDispatcher : NSObject - -@property (nonatomic, copy) DispatcherCallback dispatcherCallback; +@interface MSALAADOauth2Provider : MSALOauth2Provider @end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/src/instance/oauth2/aad/MSALAADOauth2Provider.m b/MSAL/src/instance/oauth2/aad/MSALAADOauth2Provider.m new file mode 100644 index 0000000000..656dc89c16 --- /dev/null +++ b/MSAL/src/instance/oauth2/aad/MSALAADOauth2Provider.m @@ -0,0 +1,190 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALAADOauth2Provider.h" +#import "MSIDAADV2Oauth2Factory.h" +#import "MSALOauth2Provider+Internal.h" +#import "MSALResult+Internal.h" +#import "MSIDAuthority.h" +#import "MSALAADAuthority.h" +#import "MSIDTokenResult.h" +#import "NSURL+MSIDAADUtils.h" +#import "MSALAccount.h" +#import "MSALAccountId.h" +#import "MSIDAADAuthority.h" +#import "MSIDDefaultTokenCacheAccessor.h" +#import "MSALErrorConverter.h" +#import "MSIDAccountMetadataCacheAccessor.h" +#import "MSALAccount+Internal.h" +#import "MSIDAccountIdentifier.h" +#import "MSIDAADV2IdTokenClaims.h" +#import "MSALTenantProfile+Internal.h" + +@implementation MSALAADOauth2Provider + +#pragma mark - Public + +- (MSALResult *)resultWithTokenResult:(MSIDTokenResult *)tokenResult + error:(NSError **)error +{ + NSError *authorityError = nil; + + MSALAADAuthority *aadAuthority = [[MSALAADAuthority alloc] initWithURL:tokenResult.authority.url error:&authorityError]; + + if (!aadAuthority) + { + MSID_LOG_WITH_CTX_PII(MSIDLogLevelWarning, nil, @"Invalid authority, error %@", MSID_PII_LOG_MASKABLE(authorityError)); + + if (error) *error = authorityError; + + return nil; + } + + return [MSALResult resultWithMSIDTokenResult:tokenResult authority:aadAuthority error:error]; +} + +- (BOOL)removeAdditionalAccountInfo:(MSALAccount *)account + error:(NSError **)error +{ + // If we remove account, we want this app to be also disassociated from foci token, so that user cannot sign in silently again after signing out + // Therefore, we update app metadata to not have family id for this app after signout + + NSURL *authorityURL = [NSURL msidAADURLWithEnvironment:account.environment tenant:account.lookupAccountIdentifier.utid]; + MSIDAADAuthority *aadAuthority = [[MSIDAADAuthority alloc] initWithURL:authorityURL rawTenant:nil context:nil error:nil]; + + NSError *metadataError = nil; + BOOL metadataResult = [self.tokenCache updateAppMetadataWithFamilyId:@"" + clientId:self.clientId + authority:aadAuthority + context:nil + error:&metadataError]; + + if (!metadataResult) + { + if (error) + { + *error = metadataError; + } + + MSID_LOG_WITH_CTX_PII(MSIDLogLevelWarning,nil, @"Failed to update app metadata when removing account %@", MSID_PII_LOG_MASKABLE(metadataError)); + return NO; + } + + return YES; +} + +- (MSIDAuthority *)issuerAuthorityWithAccount:(MSALAccount *)account + requestAuthority:(MSIDAuthority *)requestAuthority + instanceAware:(BOOL)instanceAware + error:(NSError **)error +{ + MSIDAuthority *authority = requestAuthority; + + if (self.accountMetadataCache) + { + NSURL *cachedURL = [self.accountMetadataCache getAuthorityURL:requestAuthority.url + homeAccountId:account.homeAccountId.identifier + clientId:self.clientId + instanceAware:instanceAware + context:nil + error:error]; + + if (cachedURL) + { + authority = [[MSIDAADAuthority alloc] initWithURL:cachedURL rawTenant:nil context:nil error:error]; + MSID_LOG_WITH_CTX(MSIDLogLevelInfo, nil, @"Request authority cache look up for %@, using %@ instead", requestAuthority.url, authority.url); + } + else if ([authority isKindOfClass:[MSIDAADAuthority class]]) + + { + /* + In the acquire token silent call we assume developer wants to get access token for account's home tenant, + if authority is a common, organizations or consumers authority. + TODO: this logic can be removed when server side issue with returning wrong id token is fixed in cross-tenant scenarios + */ + MSIDAADAuthority *aadAuthority = (MSIDAADAuthority *)authority; + + if (aadAuthority.tenant.type == MSIDAADTenantTypeCommon + || aadAuthority.tenant.type == MSIDAADTenantTypeConsumers + || aadAuthority.tenant.type == MSIDAADTenantTypeOrganizations) + { + // This is just a precaution to ensure tenantId is a valid AAD tenant semantically + NSUUID *tenantUUID = [[NSUUID alloc] initWithUUIDString:account.homeAccountId.tenantId]; + + if (tenantUUID) + { + authority = [[MSIDAADAuthority alloc] initWithURL:authority.url rawTenant:account.homeAccountId.tenantId context:nil error:error]; + } + else + { + MSID_LOG_WITH_CTX_PII(MSIDLogLevelWarning, nil, @"Unexpected tenantId found %@", MSID_PII_LOG_MASKABLE(account.homeAccountId.tenantId)); + } + + authority = [[MSIDAADAuthority alloc] initWithURL:authority.url rawTenant:account.homeAccountId.tenantId context:nil error:error]; + } + + MSID_LOG_WITH_CTX(MSIDLogLevelInfo, nil, @"Didn't find cached authority for %@. Falling back to home authority instead %@", requestAuthority.url, authority.url); + } + } + + return authority; +} + +- (BOOL)isSupportedAuthority:(MSIDAuthority *)authority +{ + return [authority isKindOfClass:[MSIDAADAuthority class]]; +} + +- (MSALTenantProfile *)tenantProfileWithClaims:(NSDictionary *)claims + homeAccountId:(MSALAccountId *)homeAccountId + environment:(NSString *)environment + error:(NSError **)error +{ + MSIDAADV2IdTokenClaims *idTokenClaims = [[MSIDAADV2IdTokenClaims alloc] initWithJSONDictionary:claims error:error]; + + if (!idTokenClaims) + { + return nil; + } + + BOOL isHomeTenantProfile = [homeAccountId.objectId isEqualToString:idTokenClaims.uniqueId]; + + return [[MSALTenantProfile alloc] initWithIdentifier:idTokenClaims.uniqueId + tenantId:idTokenClaims.realm + environment:environment + isHomeTenantProfile:isHomeTenantProfile + claims:claims]; +} + +#pragma mark - Protected + +- (void)initOauth2Factory +{ + self.msidOauth2Factory = [MSIDAADV2Oauth2Factory new]; +} + +@end diff --git a/MSAL/src/instance/oauth2/adfs/MSALADFSOauth2Provider.h b/MSAL/src/instance/oauth2/adfs/MSALADFSOauth2Provider.h new file mode 100644 index 0000000000..09d3bd61a2 --- /dev/null +++ b/MSAL/src/instance/oauth2/adfs/MSALADFSOauth2Provider.h @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALOauth2Provider.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MSALADFSOauth2Provider : MSALOauth2Provider + +@end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/src/instance/oauth2/adfs/MSALADFSOauth2Provider.m b/MSAL/src/instance/oauth2/adfs/MSALADFSOauth2Provider.m new file mode 100644 index 0000000000..939ad236ae --- /dev/null +++ b/MSAL/src/instance/oauth2/adfs/MSALADFSOauth2Provider.m @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALADFSOauth2Provider.h" +#import "MSALResult+Internal.h" +#import "MSIDAuthority.h" +#import "MSALADFSAuthority.h" +#import "MSIDTokenResult.h" +#import "MSIDADFSAuthority.h" +#import "MSALAccount+Internal.h" + +@implementation MSALADFSOauth2Provider + +#pragma mark - Public + +- (MSALResult *)resultWithTokenResult:(MSIDTokenResult *)tokenResult + error:(NSError **)error +{ + NSError *authorityError = nil; + + MSALADFSAuthority *adfsAuthority = [[MSALADFSAuthority alloc] initWithURL:tokenResult.authority.url error:&authorityError]; + + if (!adfsAuthority) + { + MSID_LOG_WITH_CTX_PII(MSIDLogLevelWarning, nil, @"Invalid authority, error %@", MSID_PII_LOG_MASKABLE(authorityError)); + + if (error) *error = authorityError; + + return nil; + } + + return [MSALResult resultWithMSIDTokenResult:tokenResult authority:adfsAuthority error:error]; +} + +- (BOOL)isSupportedAuthority:(MSIDAuthority *)authority +{ + return [authority isKindOfClass:[MSIDADFSAuthority class]]; +} + +#pragma mark - Protected + +- (void)initOauth2Factory +{ + NSAssert(NO, @"ADFS still unimplemented! Implement me."); +} + +@end diff --git a/MSAL/src/instance/oauth2/b2c/MSALB2COauth2Provider.h b/MSAL/src/instance/oauth2/b2c/MSALB2COauth2Provider.h new file mode 100644 index 0000000000..01de1393c8 --- /dev/null +++ b/MSAL/src/instance/oauth2/b2c/MSALB2COauth2Provider.h @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALOauth2Provider.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MSALB2COauth2Provider : MSALOauth2Provider + +@end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/src/instance/oauth2/b2c/MSALB2COauth2Provider.m b/MSAL/src/instance/oauth2/b2c/MSALB2COauth2Provider.m new file mode 100644 index 0000000000..c4dc8712cb --- /dev/null +++ b/MSAL/src/instance/oauth2/b2c/MSALB2COauth2Provider.m @@ -0,0 +1,123 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALB2COauth2Provider.h" +#import "MSALOauth2Provider+Internal.h" +#import "MSIDB2COauth2Factory.h" +#import "MSALResult+Internal.h" +#import "MSIDAuthority.h" +#import "MSALB2CAuthority_Internal.h" +#import "MSIDTokenResult.h" +#import "MSIDB2CAuthority.h" +#import "MSALAccount.h" +#import "MSALAccountId.h" +#import "MSIDAccountMetadataCacheAccessor.h" +#import "MSALAccount+Internal.h" +#import "MSIDAccountIdentifier.h" +#import "MSIDB2CIdTokenClaims.h" +#import "MSALTenantProfile+Internal.h" + +@implementation MSALB2COauth2Provider + +#pragma mark - Public + +- (MSALResult *)resultWithTokenResult:(MSIDTokenResult *)tokenResult + error:(NSError **)error +{ + NSError *authorityError = nil; + + MSALB2CAuthority *b2cAuthority = [[MSALB2CAuthority alloc] initWithURL:tokenResult.authority.url validateFormat:NO error:&authorityError]; + + if (!b2cAuthority) + { + MSID_LOG_WITH_CTX_PII(MSIDLogLevelWarning, nil, @"Invalid authority, error %@", MSID_PII_LOG_MASKABLE(authorityError)); + + if (error) *error = authorityError; + + return nil; + } + + return [MSALResult resultWithMSIDTokenResult:tokenResult authority:b2cAuthority error:error]; +} + +- (MSIDAuthority *)issuerAuthorityWithAccount:(MSALAccount *)account + requestAuthority:(MSIDAuthority *)requestAuthority + instanceAware:(BOOL)instanceAware + error:(NSError **)error +{ + if (self.accountMetadataCache) + { + NSURL *cachedURL = [self.accountMetadataCache getAuthorityURL:requestAuthority.url + homeAccountId:account.homeAccountId.identifier + clientId:self.clientId + instanceAware:instanceAware + context:nil + error:error]; + + MSIDAuthority *cachedAuthority = + [[MSIDB2CAuthority alloc] initWithURL:cachedURL?:requestAuthority.url + validateFormat:NO rawTenant:nil context:nil error:error]; + + MSID_LOG_WITH_CTX(MSIDLogLevelInfo, nil, @"Request authority cache look up for %@, using %@ instead", requestAuthority.url, cachedAuthority.url); + + return cachedAuthority; + } + return requestAuthority; +} + +- (BOOL)isSupportedAuthority:(MSIDAuthority *)authority +{ + return [authority isKindOfClass:[MSIDB2CAuthority class]]; +} + +- (MSALTenantProfile *)tenantProfileWithClaims:(NSDictionary *)claims + homeAccountId:(__unused MSALAccountId *)homeAccountId + environment:(NSString *)environment + error:(NSError **)error +{ + MSIDB2CIdTokenClaims *idTokenClaims = [[MSIDB2CIdTokenClaims alloc] initWithJSONDictionary:claims error:error]; + + if (!idTokenClaims) + { + return nil; + } + + return [[MSALTenantProfile alloc] initWithIdentifier:idTokenClaims.uniqueId + tenantId:idTokenClaims.realm + environment:environment + isHomeTenantProfile:YES + claims:claims]; +} + +#pragma mark - Protected + +- (void)initOauth2Factory +{ + self.msidOauth2Factory = [MSIDB2COauth2Factory new]; +} + +@end diff --git a/MSAL/src/public/MSAL.h b/MSAL/src/public/MSAL.h index d96ab877bb..f4f1f502a1 100644 --- a/MSAL/src/public/MSAL.h +++ b/MSAL/src/public/MSAL.h @@ -53,6 +53,7 @@ FOUNDATION_EXPORT const unsigned char MSAL__Framework_VersionString[]; #import #import #import +#import #import #import #import @@ -68,4 +69,11 @@ FOUNDATION_EXPORT const unsigned char MSAL__Framework_VersionString[]; #import #import #import - +#import +#import +#import +#import +#import +#if TARGET_OS_IPHONE +#import +#endif diff --git a/MSAL/src/public/MSALAADAuthority.h b/MSAL/src/public/MSALAADAuthority.h index a950f4c703..2b47fad6b7 100644 --- a/MSAL/src/public/MSALAADAuthority.h +++ b/MSAL/src/public/MSALAADAuthority.h @@ -28,13 +28,113 @@ #import #import "MSALAuthority.h" +/* +The sign-in audience specifies what kind of accounts you want to support in your app depending on the business needs for your application: + + For example, if you're building an application that will be only used in your organization, you can specify MSALAudienceType as MSALAzureADMyOrgOnlyAudience, and specify what organization it is by passing its tenant ID + + If your app will be used by multiple organizations and you want to sign-in users with both their work and school accopunts, you can specify MSALAudienceType as MSALAzureADAndPersonalMicrosoftAccountAudience. + + Note that effective audience will be also dependent on what you specify in your application registration. For example, if you specify sign in audience as My Org Only in your app registration, and in MSAL as Multiple Orgs, the effective audience for your application will be the minimum of those two (My Org Only). See instructions here: https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app#register-a-new-application-using-the-azure-portal*/ + +typedef NS_ENUM(NSInteger, MSALAudienceType) +{ + +/* Users with a personal Microsoft account, or a work or school account in any organization’s Azure AD tenant + Maps to https://[instance]/common/ +*/ + MSALAzureADAndPersonalMicrosoftAccountAudience, + +/* + Users with a Microsoft work or school account in any organization’s Azure AD tenant (i.e. multi-tenant). + Maps to https://[instance]/organizations/ +*/ + MSALAzureADMultipleOrgsAudience, + +/* Users with a Microsoft work or school account in my organization’s Azure AD tenant (i.e. single tenant). + Maps to https://[instance]/[tenantId] + */ + MSALAzureADMyOrgOnlyAudience, + +/* + Users with a personal Microsoft account. Maps to https://[instance]/consumers/ + */ + MSALPersonalMicrosoftAccountAudience +}; + +typedef NS_ENUM(NSInteger, MSALAzureCloudInstance) +{ + // Microsoft Azure public cloud. Maps to https://login.microsoftonline.com + MSALAzurePublicCloudInstance, + + // Microsoft Chinese national cloud. Maps to https://login.chinacloudapi.cn + MSALAzureChinaCloudInstance, + + // Microsoft German national cloud ("Black Forest"). Maps to https://login.microsoftonline.de + MSALAzureGermanyCloudInstance, + + // US Government cloud. Maps to https://login.microsoftonline.us + MSALAzureUsGovernmentCloudInstance +}; + @interface MSALAADAuthority : MSALAuthority +/* + Initializes MSALAADAuthority with NSURL. + @param url Authority indicating a directory that MSAL can use to obtain tokens. In Azure AD + it is of the form https:///, where is the + directory host (e.g. https://login.microsoftonline.com) and is a + identifier within the directory itself (e.g. a domain associated to the + tenant, such as contoso.onmicrosoft.com, or the GUID representing the + TenantID property of the directory) + @param error The error that occurred creating the application object, if any, if you're + not interested in the specific error pass in nil. + */ - (nullable instancetype)initWithURL:(nonnull NSURL *)url error:(NSError * _Nullable __autoreleasing * _Nullable)error; +/* + Initializes MSALAADAuthority with NSURL and tenant ID. + @param url Authority indicating a directory that MSAL can use to obtain tokens. In Azure AD + it is of the form https:///, where is the + directory host (e.g. https://login.microsoftonline.com) and is a + identifier within the directory itself (e.g. a domain associated to the + tenant, such as contoso.onmicrosoft.com, or the GUID representing the + TenantID property of the directory) + @param rawTenant GUID representing the TenantID of your Azure Active Directory + @param error The error that occurred creating the application object, if any, if you're + not interested in the specific error pass in nil. + */ - (nullable instancetype)initWithURL:(nonnull NSURL *)url rawTenant:(nullable NSString *)rawTenant error:(NSError * _Nullable __autoreleasing * _Nullable)error NS_DESIGNATED_INITIALIZER; +/* + Initializes MSALAADAuthority with a cloud instance, audience type and an optional tenant ID. + @param cloudInstance Azure AD authentication endpoint in a national cloud. + @param audienceType The sign-in audience for the authority. + @param rawTenant GUID representing the TenantID of your Azure Active Directory + @param error The error that occurred creating the application object, if any, if you're + not interested in the specific error pass in nil. + */ +- (nullable instancetype)initWithCloudInstance:(MSALAzureCloudInstance)cloudInstance + audienceType:(MSALAudienceType)audienceType + rawTenant:(nullable NSString *)rawTenant + error:(NSError * _Nullable __autoreleasing * _Nullable)error; + +/* + Initializes MSALAADAuthority with a cloud instance, audience type and an optional tenant ID. + @param environment Host of Azure AD authentication endpoint in a national cloud (e.g. "login.microsoftonline.com" or "login.microsoftonline.de") + @param audienceType The sign-in audience for the authority. + @param rawTenant GUID representing the TenantID of your Azure Active Directory + @param error The error that occurred creating the application object, if any, if you're + not interested in the specific error pass in nil. + */ +- (nullable instancetype)initWithEnvironment:(nonnull NSString *)environment + audienceType:(MSALAudienceType)audienceType + rawTenant:(nullable NSString *)rawTenant + error:(NSError * _Nullable __autoreleasing * _Nullable)error; + + + @end diff --git a/MSAL/src/public/MSALAccount+MultiTenantAccount.h b/MSAL/src/public/MSALAccount+MultiTenantAccount.h new file mode 100644 index 0000000000..1827a77b6b --- /dev/null +++ b/MSAL/src/public/MSALAccount+MultiTenantAccount.h @@ -0,0 +1,54 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALAccount.h" + +@class MSALTenantProfile; +@class MSALAccountId; + +@interface MSALAccount (MultiTenantAccount) + +/*! + Array of all tenants for which a token has been requested by the client. + + Note that this field will only be available when querying account(s) by the following APIs of MSALPublicClientApplication: + -allAccounts: + -accountForHomeAccountId:error: + -accountForUsername:error: + -allAccountsFilteredByAuthority: + + The field will be nil in other scenarios. E.g., account returned as part of the result of an acquire token interactive/silent call. + */ +@property (readonly, nullable) NSArray *tenantProfiles; + +/*! + Unique identifier of the account in the home tenant. + Provides additional information regarding account's home objectId and home tenantId in case of AAD. + */ +@property (readonly, nullable) MSALAccountId *homeAccountId; + +@end diff --git a/MSAL/src/public/MSALAccount.h b/MSAL/src/public/MSALAccount.h index 9791f331c6..97cd400a62 100644 --- a/MSAL/src/public/MSALAccount.h +++ b/MSAL/src/public/MSALAccount.h @@ -27,24 +27,57 @@ #import -@class MSALAccountId; +@class MSALPublicClientApplication; -@interface MSALAccount : NSObject +@protocol MSALAccount /*! - The displayable value in UserPrincipleName(UPN) format. Can be nil if not returned from the service. + Shorthand name by which the End-User wishes to be referred to at the RP, such as janedoe or j.doe. This value MAY be any valid JSON string including special characters such as @, /, or whitespace. + Mostly maps to UserPrincipleName(UPN) in case of AAD. + Can be nil if not returned from the service. */ @property (readonly, nullable) NSString *username; /*! - Unique identifier of the account in the home directory. + Unique identifier for the account. + Save this for account lookups from cache at a later point. */ -@property (readonly, nullable) MSALAccountId *homeAccountId; +@property (readonly, nullable) NSString *identifier; /*! - Host part of the authority string used for authentication. + Host part of the authority string used for authentication based on the issuer identifier. + Note that if a host supports multiple tenants, there'll be one MSALAccount for the host and one tenant profile per each tenant accessed (see MSALAccount+MultiTenantAccount.h header) + If a host doesn't support multiple tenants, there'll be one MSALAccount with accountClaims returned. + + e.g. if app accesses following tenants: Contoso.com and MyOrg.com in the Public AAD cloud, there'll be following information returned: + + MSALAccount + - environment of "login.microsoftonline.com" + - identifier based on the GUID of "MyOrg.com" + - accountClaims from the id token for the "MyOrg.com" + - tenantProfiles + - tenantProfile[0] + - identifier based on account identifiers from "MyOrg.com" (account object id in MyOrg.com and tenant Id for MyOrg.com directory) + - claims for the id token issued by MyOrg.com + - tenantProfile[1] + - identifier based on account identifiers from "Contoso.com" + - claims for the id token issued by Contoso.com */ @property (readonly, nonnull) NSString *environment; +/*! + ID token claims for the account. + Can be used to read additional information about the account, e.g. name + Will only be returned if there has been an id token issued for the client Id for the account's source tenant. + */ +@property (readonly, nullable) NSDictionary *accountClaims; + +@end + +@interface MSALAccount : NSObject + ++ (nonnull instancetype)new NS_UNAVAILABLE; +- (nonnull instancetype)init NS_UNAVAILABLE; + @end diff --git a/MSAL/src/public/MSALAccountEnumerationParameters.h b/MSAL/src/public/MSALAccountEnumerationParameters.h new file mode 100644 index 0000000000..3b83b9ba39 --- /dev/null +++ b/MSAL/src/public/MSALAccountEnumerationParameters.h @@ -0,0 +1,64 @@ +//------------------------------------------------------------------------------ +// +// 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 + +@interface MSALAccountEnumerationParameters : NSObject + +/*! + Unique identifier for the account. + */ +@property (nonatomic, readonly, nullable) NSString *identifier; + +/*! + Unique identifier for the tenant profile. + */ +@property (nonatomic, readonly, nullable) NSString *tenantProfileIdentifier; + +/*! + Shorthand name by which the End-User wishes to be referred to at the RP, such as janedoe or j.doe. + */ +@property (nonatomic, readonly, nullable) NSString *username; + +/*! + Filter accounts by whether this account is in the signed in state for the current client. + Signed in state is determined by the presence of a refresh token credential for the requesting client. + If account has been explicitly removed through the "removeAccount" API, it will be also marked as "signed out" as MSAL will remove refresh token for the client. + + YES by default (== only returns signed in accounts). + Set it to NO to query all accounts visible to your application regardless if there's a refresh token present or not. + */ +@property (nonatomic, readwrite) BOOL returnOnlySignedInAccounts; + +- (nonnull instancetype)initWithIdentifier:(nonnull NSString *)accountIdentifier; + +- (nonnull instancetype)initWithIdentifier:(nullable NSString *)accountIdentifier + username:(nonnull NSString *)username; + +- (nonnull instancetype)initWithTenantProfileIdentifier:(nonnull NSString *)tenantProfileIdentifier; + +@end diff --git a/MSAL/src/public/MSALAccountId.h b/MSAL/src/public/MSALAccountId.h index 4aacd26cec..9269423058 100644 --- a/MSAL/src/public/MSALAccountId.h +++ b/MSAL/src/public/MSALAccountId.h @@ -31,7 +31,7 @@ @property (nonatomic, readonly, nonnull) NSString *identifier; /*! - Object id of the account in the directory + Object id of the account in the tenant */ @property (nonatomic, readonly, nullable) NSString *objectId; diff --git a/MSAL/src/public/MSALDefinitions.h b/MSAL/src/public/MSALDefinitions.h index 5487c30751..ee7f78b23e 100644 --- a/MSAL/src/public/MSALDefinitions.h +++ b/MSAL/src/public/MSALDefinitions.h @@ -97,7 +97,7 @@ typedef NS_ENUM(NSUInteger, MSALPromptType) If multiple users are signed in, select account experience will be presented. */ MSALPromptTypePromptIfNecessary, - MSALPromptTypeDefault = MSALPromptTypeSelectAccount, + MSALPromptTypeDefault = MSALPromptTypePromptIfNecessary, }; typedef void (^MSALCompletionBlock)(MSALResult * _Nullable result, NSError * _Nullable error); @@ -110,12 +110,18 @@ typedef void (^MSALAccountsCompletionBlock)(NSArray * _Nullable a @param level The level of the log message @param message The message being logged @param containsPII If the message might contain Personally Identifiable Information (PII) - this will be true. Log messages possibly containing PII will not be - sent to the callback unless PIllLoggingEnabled is set to YES on the - logger. + this will be true. Log messages possibly containing PII will not be + sent to the callback unless PIllLoggingEnabled is set to YES on the + logger. */ typedef void (^MSALLogCallback)(MSALLogLevel level, NSString * _Nullable message, BOOL containsPII); +/*! + MSAL telemetry callback. + + @param event Aggregated telemetry event. + */ +typedef void(^MSALTelemetryCallback)(NSDictionary * _Nonnull event); #endif /* MSALConstants_h */ diff --git a/MSAL/src/public/MSALError.h b/MSAL/src/public/MSALError.h index b931f741a0..f05e223f97 100644 --- a/MSAL/src/public/MSALError.h +++ b/MSAL/src/public/MSALError.h @@ -220,6 +220,11 @@ typedef NS_ENUM(NSInteger, MSALInternalError) */ MSALInternalErrorUnhandledResponse = -42007, + /*! + An unexpected error occured within the MSAL client. + */ + MSALInternalErrorUnexpected = -42008, + /*! The passed in authority URL does not pass validation. If you're trying to use B2C, you must disable authority validation by diff --git a/MSAL/src/public/MSALInteractiveTokenParameters.h b/MSAL/src/public/MSALInteractiveTokenParameters.h index 4b3a6ea9c2..5f128e86f9 100644 --- a/MSAL/src/public/MSALInteractiveTokenParameters.h +++ b/MSAL/src/public/MSALInteractiveTokenParameters.h @@ -70,8 +70,25 @@ NS_ASSUME_NONNULL_BEGIN */ - (instancetype)initWithScopes:(NSArray *)scopes NS_DESIGNATED_INITIALIZER; -@property (nonatomic, nullable) WKWebView *customWebview; +#if TARGET_OS_IPHONE +/*! + Modal presentation style for displaying authentication web content. + */ +@property (nullable, weak, nonatomic) UIViewController *parentViewController; +@property (nonatomic) UIModalPresentationStyle presentationStyle; +#endif + +/*! + A specific webView type for the interactive authentication flow. + By default, it will be set to MSALGlobalConfig.defaultWebviewType. + */ @property (nonatomic) MSALWebviewType webviewType; +/*! + For a webviewType MSALWebviewTypeWKWebView, custom WKWebView can be passed on. + Web content will be rendered onto this view. + Observe strings declared in MSALPublicClientStatusNotifications to know when to dismiss. + */ +@property (nonatomic, nullable) WKWebView *customWebview; @end diff --git a/MSAL/src/public/MSALPublicClientApplication.h b/MSAL/src/public/MSALPublicClientApplication.h index 9ede961011..855a2d803f 100644 --- a/MSAL/src/public/MSALPublicClientApplication.h +++ b/MSAL/src/public/MSALPublicClientApplication.h @@ -38,6 +38,7 @@ @class MSALSilentTokenParameters; @class MSALInteractiveTokenParameters; @class MSALClaimsRequest; +@class MSALAccountEnumerationParameters; @interface MSALPublicClientApplication : NSObject @@ -142,8 +143,9 @@ #if TARGET_OS_IPHONE /*! - The keychain sharing group to use for the token cache. - If it is nil, default MSAL group will be used. + The current keychain sharing group used for the token cache. + If it is nil, it means keychain sharing is disabled. Please + refer to MSALCacheConfig for more details. */ @property (nonatomic, readonly, nullable) NSString *keychainGroup; @@ -151,8 +153,8 @@ Initialize a MSALPublicClientApplication with a given clientID and keychain group @param clientId The clientID of your application, you should get this from the app portal. - @param keychainGroup The keychain sharing group to use for the token cache. (optional) - If you provide this key, you MUST add the capability to your Application Entilement. + @param keychainGroup The keychain sharing group to use for the token cache. Pass nil to disable + keychain sharing. @param error The error that occurred creating the application object, if any (optional) */ - (nullable instancetype)initWithClientId:(nonnull NSString *)clientId @@ -163,8 +165,8 @@ Initialize a MSALPublicClientApplication with a given clientID, authority and keychain group @param clientId The clientID of your application, you should get this from the app portal. - @param keychainGroup The keychain sharing group to use for the token cache. (optional) - If you provide this key, you MUST add the capability to your Application Entilement. + @param keychainGroup The keychain sharing group to use for the token cache. Pass nil to disable + keychain sharing. @param authority Authority indicating a directory that MSAL can use to obtain tokens. In Azure AD it is of the form https://, where is the directory host (e.g. https://login.microsoftonline.com) and is a @@ -183,8 +185,8 @@ Initialize a MSALPublicClientApplication with a given clientID, authority, keychain group and redirect uri @param clientId The clientID of your application, you should get this from the app portal. - @param keychainGroup The keychain sharing group to use for the token cache. (optional) - If you provide this key, you MUST add the capability to your Application Entilement. + @param keychainGroup The keychain sharing group to use for the token cache. Pass nil to disable + keychain sharing. @param authority Authority indicating a directory that MSAL can use to obtain tokens. In Azure AD it is of the form https://, where is the directory host (e.g. https://login.microsoftonline.com) and is a @@ -212,13 +214,32 @@ - (nullable NSArray *)allAccounts:(NSError * _Nullable __autoreleasing * _Nullable)error; /*! - Returns account for for the given home identifier (received from an account object returned in a previous acquireToken call) + Returns account for the given home identifier (received from an account object returned in a previous acquireToken call) @param error The error that occured trying to get the accounts, if any, if you're not interested in the specific error pass in nil. */ - (nullable MSALAccount *)accountForHomeAccountId:(nonnull NSString *)homeAccountId - error:(NSError * _Nullable __autoreleasing * _Nullable)error; + error:(NSError * _Nullable __autoreleasing * _Nullable)error DEPRECATED_MSG_ATTRIBUTE("Use [MSALPublicClientApplication accountForIdentifier:error:] instead"); + +/*! + Returns account for the given account identifier (received from an account object returned in a previous acquireToken call) + + @param error The error that occured trying to get the accounts, if any, if you're + not interested in the specific error pass in nil. + */ +- (nullable MSALAccount *)accountForIdentifier:(nonnull NSString *)identifier + error:(NSError * _Nullable __autoreleasing * _Nullable)error; + +/*! + Returns account for the given account identifying parameters (received from an account object returned in a previous acquireToken call) + + @param error The error that occured trying to get the accounts, if any, if you're + not interested in the specific error pass in nil. + */ +- (nullable NSArray *)accountsForParameters:(nonnull MSALAccountEnumerationParameters *)parameters + error:(NSError * _Nullable __autoreleasing * _Nullable)error; + /*! Returns account for for the given username (received from an account object returned in a previous acquireToken call or ADAL) @@ -625,7 +646,8 @@ /*! Removes all tokens from the cache for this application for the provided account - User will need to enter his credentials again after calling this API + MSAL won't be able to return tokens silently after calling this API, and developer will need to call acquireToken + User might need to enter his credentials again after calling this API @param account The account to remove from the cache */ diff --git a/MSAL/src/public/MSALRedirectUri.h b/MSAL/src/public/MSALRedirectUri.h index 0c74db5e79..5f792419c9 100644 --- a/MSAL/src/public/MSALRedirectUri.h +++ b/MSAL/src/public/MSALRedirectUri.h @@ -35,7 +35,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) NSURL *url; /* Indicates if redirect URI can be used with broker - Broker redirect URIs need to follow particular format, e.g. msauth://auth */ + Broker redirect URIs need to follow particular format, e.g. msauth.://auth */ @property (nonatomic, readonly) BOOL brokerCapable; @end diff --git a/MSAL/src/public/MSALResult.h b/MSAL/src/public/MSALResult.h index 8fc41c3279..afd2508bc1 100644 --- a/MSAL/src/public/MSALResult.h +++ b/MSAL/src/public/MSALResult.h @@ -29,6 +29,7 @@ @class MSALAccount; @class MSALAuthority; +@class MSALTenantProfile; @interface MSALResult : NSObject @@ -50,22 +51,27 @@ /*! An identifier for the tenant that the token was acquired from. This property will be nil if tenant information is not returned by the service. */ -@property (readonly, nullable) NSString *tenantId; +@property (readonly, nullable) NSString *tenantId DEPRECATED_MSG_ATTRIBUTE("Use MSALTenantProfile.tenantId instead"); /*! - The account object that holds account information. + The raw id token if it's returned by the service or nil if no id token is returned. */ -@property (readonly, nonnull) MSALAccount *account; +@property (readonly, nullable) NSString *idToken; /*! - The raw id token if it's returned by the service or nil if no id token is returned. -*/ -@property (readonly, nullable) NSString *idToken; + A tenant profile object that contains all the tenant-specific information, including tenant id, user object id, etc. It also contains all the id token claims as a dictionary. + */ +@property (readonly, nonnull) MSALTenantProfile *tenantProfile; /*! - The unique id of the user. + The account object that holds account information. */ -@property (readonly, nullable) NSString *uniqueId; +@property (readonly, nonnull) MSALAccount *account; + +/*! + The unique id of the account. + */ +@property (readonly, nullable) NSString *uniqueId DEPRECATED_MSG_ATTRIBUTE("Use MSALTenantProfile.tenantProfileId instead"); /*! The scope values returned from the service. @@ -75,8 +81,13 @@ /*! Represents the authority used for getting the token from STS and caching it. This authority should be used for subsequent silent requests. - It will be different from the authority provided by developer for sovereign cloud scenarios. + It might be different from the authority provided by developer (e.g. for sovereign cloud scenarios). */ @property (readonly, nonnull) MSALAuthority *authority; +/*! + The correlation ID of the request. + */ +@property (readonly, nonnull) NSUUID *correlationId; + @end diff --git a/MSAL/src/public/MSALTelemetry.h b/MSAL/src/public/MSALTelemetry.h index 7b197bf267..1f18ba1bde 100644 --- a/MSAL/src/public/MSALTelemetry.h +++ b/MSAL/src/public/MSALTelemetry.h @@ -21,48 +21,44 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#import "MSALTelemetryConfig.h" +#import + +NS_ASSUME_NONNULL_BEGIN /*! @class MSALTelemetry The central class for MSAL telemetry. - Usage: Get a singleton instance of MSALTelemetry; register a dispatcher for receiving telemetry events. + Usage: Get a singleton instance of MSALTelemetry; register an observer for receiving telemetry events. */ @interface MSALTelemetry : NSObject -+ (nonnull instancetype)new __attribute__((unavailable("new is unavailable, use sharedInstance instead."))); -- (nonnull instancetype)init __attribute__((unavailable("init is unavailable, use sharedInstance instead."))); +- (nonnull instancetype)init NS_UNAVAILABLE; ++ (nonnull instancetype)new NS_UNAVAILABLE; /*! Get a singleton instance of MSALTelemetry. */ -+ (nonnull MSALTelemetry *)sharedInstance DEPRECATED_MSG_ATTRIBUTE("use MSALGlobalConfig.telemetryConfig instead"); ++ (nonnull MSALTelemetry *)sharedInstance DEPRECATED_MSG_ATTRIBUTE("use MSALGlobalConfig.telemetryConfig instead"); /*! Setting piiEnabled to YES, will allow MSAL to return fields with user information in the telemetry events. MSAL does not send telemetry data by itself to any server. If apps want to collect MSAL telemetry with user information they must setup the telemetry callback and set this flag on. By default MSAL will not return any user information in telemetry. */ -@property (nonatomic) BOOL piiEnabled DEPRECATED_MSG_ATTRIBUTE("use MSALGlobalConfig.telemetryConfig.piiEnabled instead"); +@property (atomic) BOOL piiEnabled DEPRECATED_MSG_ATTRIBUTE("use MSALGlobalConfig.telemetryConfig.piiEnabled instead"); /*! - Register a telemetry dispatcher for receiving telemetry events. - @param dispatcher An instance of MSALTelemetryDispatcher implementation. - @param setTelemetryOnFailure If set YES, telemetry events are only dispatched when errors occurred; - If set NO, MSAL will dispatch will dispatch all events. + If set YES, telemetry events are only dispatched when errors occurred; + If set NO, MSAL will dispatch all events. */ -- (void)addDispatcher:(nonnull id)dispatcher -setTelemetryOnFailure:(BOOL)setTelemetryOnFailure DEPRECATED_MSG_ATTRIBUTE("use MSALGlobalConfig.telemetryConfig addDispatcher:setTelemetryOnFailure: instead"); +@property (atomic) BOOL notifyOnFailureOnly DEPRECATED_MSG_ATTRIBUTE("use MSALGlobalConfig.telemetryConfig.notifyOnFailureOnly instead"); /*! - Remove a telemetry dispatcher added for receiving telemetry events. - @param dispatcher An instance of MSALTelemetryDispatcher implementation added to the dispatches before. + Invoked when telemetry data is received. */ -- (void)removeDispatcher:(nonnull id)dispatcher DEPRECATED_MSG_ATTRIBUTE("use MSALGlobalConfig.telemetryConfig removeDispatcher: instead"); +@property (atomic, copy, nullable) MSALTelemetryCallback telemetryCallback DEPRECATED_MSG_ATTRIBUTE("use MSALGlobalConfig.telemetryConfig.telemetryCallback instead"); -/*! - Remove all telemetry dispatchers added to the dispatchers collection. - */ -- (void)removeAllDispatchers DEPRECATED_MSG_ATTRIBUTE("use MSALGlobalConfig.telemetryConfig removeDispatcher: instead"); @end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/src/public/MSALTenantProfile.h b/MSAL/src/public/MSALTenantProfile.h new file mode 100644 index 0000000000..255373b65e --- /dev/null +++ b/MSAL/src/public/MSALTenantProfile.h @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// 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. +// +//------------------------------------------------------------------------------ + +@class MSALAuthority; +@class MSALAccountId; + +NS_ASSUME_NONNULL_BEGIN + +@interface MSALTenantProfile : NSObject + +/*! + Unique identifier for the tenant profile. + */ +@property (readonly, nullable) NSString *identifier; + +/*! + Host part of the authority. + */ +@property (readonly, nullable) NSString *environment; + +/*! + Identifier for the directory where account is locally represented + */ +@property (readonly, nullable) NSString *tenantId; + +/*! + Indicator if this tenant profile represents account's home tenant. + If an admin deletes this account from the tenant, it prevents this account from accessing anything in any tenant with the Microsoft Identity Platform. + */ +@property (readonly) BOOL isHomeTenantProfile; + +/*! + ID token claims for the account in the specified tenant. +*/ +@property (readonly, nullable) NSDictionary *claims; + +@end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/src/public/configuration/global/MSALLoggerConfig.h b/MSAL/src/public/configuration/global/MSALLoggerConfig.h index e602b783d1..607ee017df 100644 --- a/MSAL/src/public/configuration/global/MSALLoggerConfig.h +++ b/MSAL/src/public/configuration/global/MSALLoggerConfig.h @@ -35,11 +35,11 @@ NS_ASSUME_NONNULL_BEGIN /*! The minimum log level for messages to be passed onto the log callback. */ -@property MSALLogLevel logLevel; +@property (atomic) MSALLogLevel logLevel; /*! MSAL provides logging callbacks that assist in diagnostics. There is a boolean value in the logging callback that indicates whether the message contains user information. If PiiLoggingEnabled is set to NO, the callback will not be triggered for log messages that contain any user information. By default the library will not return any messages with user information in them. */ -@property BOOL piiEnabled; +@property (atomic) BOOL piiEnabled; /*! Sets the callback block to send MSAL log messages to. diff --git a/MSAL/src/public/configuration/global/MSALTelemetryConfig.h b/MSAL/src/public/configuration/global/MSALTelemetryConfig.h index 4c39fcde1b..9ae4d6fabb 100644 --- a/MSAL/src/public/configuration/global/MSALTelemetryConfig.h +++ b/MSAL/src/public/configuration/global/MSALTelemetryConfig.h @@ -26,24 +26,7 @@ //------------------------------------------------------------------------------ #import - - -/*! - @protocol MSALTelemetryDispatcher - - Developer should implement it in order to receive telemetry events. - - Usage: an instance of MSALTelemetryDispatcher implementation is required when registerring dispatcher for MSALTelemetry. - */ -@protocol MSALTelemetryDispatcher - -/*! - Callback function that will be called by MSAL when telemetry events are flushed. - @param events events is represented by an array of dictionary of key-value pair of event property name/value. - */ -- (void)dispatchEvent:(nonnull NSArray *> *)events; - -@end +#import "MSALDefinitions.h" NS_ASSUME_NONNULL_BEGIN @@ -52,26 +35,18 @@ NS_ASSUME_NONNULL_BEGIN /*! Setting piiEnabled to YES, will allow MSAL to return fields with user information in the telemetry events. MSAL does not send telemetry data by itself to any server. If apps want to collect MSAL telemetry with user information they must setup the telemetry callback and set this flag on. By default MSAL will not return any user information in telemetry. */ -@property BOOL piiEnabled; - -/*! - Register a telemetry dispatcher for receiving telemetry events. - @param dispatcher An instance of MSALTelemetryDispatcher implementation. - @param setTelemetryOnFailure If set YES, telemetry events are only dispatched when errors occurred; - If set NO, MSAL will dispatch will dispatch all events. - */ -- (void)addDispatcher:(nonnull id)dispatcher setTelemetryOnFailure:(BOOL)setTelemetryOnFailure; +@property (atomic) BOOL piiEnabled; /*! - Remove a telemetry dispatcher added for receiving telemetry events. - @param dispatcher An instance of MSALTelemetryDispatcher implementation added to the dispatches before. + If set YES, telemetry events are only dispatched when errors occurred; + If set NO, MSAL will dispatch all events. */ -- (void)removeDispatcher:(nonnull id)dispatcher; +@property (atomic) BOOL notifyOnFailureOnly; /*! - Remove all telemetry dispatchers added to the dispatchers collection. + Invoked when telemetry data is received. */ -- (void)removeAllDispatchers; +@property (atomic, copy, nullable) MSALTelemetryCallback telemetryCallback; - (nonnull instancetype)init NS_UNAVAILABLE; + (nonnull instancetype)new NS_UNAVAILABLE; diff --git a/MSAL/src/public/configuration/publicClientApplication/cache/MSALCacheConfig.h b/MSAL/src/public/configuration/publicClientApplication/cache/MSALCacheConfig.h new file mode 100644 index 0000000000..1f866bafa7 --- /dev/null +++ b/MSAL/src/public/configuration/publicClientApplication/cache/MSALCacheConfig.h @@ -0,0 +1,77 @@ +//------------------------------------------------------------------------------ +// +// 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 + +@protocol MSALExternalAccountProviding; +@class MSALSerializedADALCacheProvider; + +NS_ASSUME_NONNULL_BEGIN + +@interface MSALCacheConfig : NSObject + +/*! + The keychain sharing group to use for the token cache. + The default value is com.microsoft.adalcache and it needs to be declared in your application's entitlements. + See more https://developer.apple.com/documentation/security/keychain_services/keychain_items/sharing_access_to_keychain_items_among_a_collection_of_apps?language=objc + */ +@property NSString *keychainSharingGroup; + +/*! + List of external account stotage providers that helps you to combine your own accounts with MSAL accounts and use a consistent API for the account management and enumeration. + Each external account provider is responsible for retrieving, enumerating, updating and removing external accounts. + Some examples where this might be useful: + 1. An app is migrating from ADAL to MSAL. Because ADAL didn't support account enumeration, developer built a separate layer to store ADAL accounts in the app. + MSAL provides account enumeration built-in. Using this API, application can let MSAL combine multiple sources of accounts and operate on a single source. + 2. An app duplicates MSAL accounts in its own account storage with some additional app specific data. + Every time when MSAL retrieves/updates an account, application wants to synchronize that account into its own account store. + */ +@property (nonatomic, readonly) NSArray> *externalAccountProviders; + +#if !TARGET_OS_IPHONE +/*! + Backward compatible ADAL serialized cache provider. + Use it if you were serializing ADAL cache on macOS and want to have backward compatibility with macOS apps. + */ +@property (nonatomic, nullable) MSALSerializedADALCacheProvider *serializedADALCache; + +#endif + +- (nonnull instancetype)init NS_UNAVAILABLE; ++ (nonnull instancetype)new NS_UNAVAILABLE; + ++ (NSString *)defaultKeychainSharingGroup; + +/*! + Adds a new external account storage provider to be used by MSAL in account retrieval. + This operation is not thread safe. + */ +- (void)addExternalAccountProvider:(id)externalAccountProvider; + +@end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/src/public/configuration/publicClientApplication/cache/MSALExternalAccountProviding.h b/MSAL/src/public/configuration/publicClientApplication/cache/MSALExternalAccountProviding.h new file mode 100644 index 0000000000..dc35e98071 --- /dev/null +++ b/MSAL/src/public/configuration/publicClientApplication/cache/MSALExternalAccountProviding.h @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// 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 + +@protocol MSALAccount; +@class MSALTenantProfile; +@class MSALAccountEnumerationParameters; + +NS_ASSUME_NONNULL_BEGIN + +/*! + Use this protocol if you have external account storage in addition to MSAL account storage. + For example, if you find yourself in situation where on each MSAL completion block invocation you are updating accounts in your own storage, + it might be beneficial to instead use MSALExternalAccountProviding extensibility feature. + */ + +@protocol MSALExternalAccountProviding + +/* + This is called when new and/or updated account is available. + */ +- (BOOL)updateAccount:(id)account + idTokenClaims:(NSDictionary *)idTokenClaims + error:(NSError * _Nullable * _Nullable)error; + +/* + This is triggered when removal of an account is necessary. + It normally happens when the app calls removeAccount API in MSAL. + But it can also happen in other circumstances when MSAL needs to cleanup account. + */ +- (BOOL)removeAccount:(id)account + tenantProfiles:(nullable NSArray *)tenantProfiles + error:(NSError * _Nullable * _Nullable)error; + +/* + This is triggered when MSAL needs to enumerate account. + Return your accounts that match parameters. + MSAL will merge external accounts with its own internal storage and return a combined list of accounts that mathes specified parameters. + */ +- (nullable NSArray> *)accountsWithParameters:(MSALAccountEnumerationParameters *)parameters + error:(NSError * _Nullable * _Nullable)error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/src/public/configuration/publicClientApplication/cache/MSALSerializedADALCacheProvider.h b/MSAL/src/public/configuration/publicClientApplication/cache/MSALSerializedADALCacheProvider.h new file mode 100644 index 0000000000..76dda7f9ad --- /dev/null +++ b/MSAL/src/public/configuration/publicClientApplication/cache/MSALSerializedADALCacheProvider.h @@ -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 + +NS_ASSUME_NONNULL_BEGIN + +@class MSALSerializedADALCacheProvider; + +@protocol MSALSerializedADALCacheProviderDelegate + +- (void)willAccessCache:(nonnull MSALSerializedADALCacheProvider *)cache; +- (void)didAccessCache:(nonnull MSALSerializedADALCacheProvider *)cache; +- (void)willWriteCache:(nonnull MSALSerializedADALCacheProvider *)cache; +- (void)didWriteCache:(nonnull MSALSerializedADALCacheProvider *)cache; + +@end + +@interface MSALSerializedADALCacheProvider : NSObject + +@property (nonatomic, nonnull, readonly) id delegate; + +- (nullable NSData *)serializeDataWithError:(NSError * _Nullable * _Nullable)error; +- (BOOL)deserialize:(nonnull NSData *)serializedData error:(NSError * _Nullable * _Nullable)error; + +- (nullable instancetype)initWithDelegate:(nonnull id)delegate + error:(NSError * _Nullable * _Nullable)error; + + +@end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/src/public/ios/cache/MSALLegacySharedAccountsProvider.h b/MSAL/src/public/ios/cache/MSALLegacySharedAccountsProvider.h new file mode 100644 index 0000000000..9db5df63e4 --- /dev/null +++ b/MSAL/src/public/ios/cache/MSALLegacySharedAccountsProvider.h @@ -0,0 +1,78 @@ +// 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 "MSALExternalAccountProviding.h" + +typedef NS_ENUM(NSInteger, MSALLegacySharedAccountMode) +{ + MSALLegacySharedAccountModeReadOnly = 0, + MSALLegacySharedAccountModeReadWrite +}; + +NS_ASSUME_NONNULL_BEGIN + +/* + Sample implementation of the MSALExternalAccountProviding protocol that can work with legacy Microsoft account storage. + Use it if: + 1. You're migrating from ADAL to MSAL and where previously relying on shared Microsoft account storage. + In that case, usage of this class should be temporary, until more than X% of users migrate to MSAL (X can be 95% depending on your app requirements). + 2. As sample code to implement your own MSALExternalAccountProviding + */ +@interface MSALLegacySharedAccountsProvider : NSObject + +/* + Specifies if MSALLegacySharedAccountsProvider will attempt to write/remove accounts. + Set to MSALLegacySharedAccountModeReadWrite to attempt writing accounts + Default is MSALLegacySharedAccountModeReadOnly, which means MSALLegacySharedAccountsProvider will not modify external account storage + */ +@property (nonatomic) MSALLegacySharedAccountMode sharedAccountMode; + +/* + Initialize new instance of MSALLegacySharedAccountsProvider. + + @param sharedGroup Specify keychain access group from which accounts will be read. + @param serviceIdentifier Specify unique account entry identifier in the keychain (each keychain entry is identifier by "account" and "service" parameters, this is the "service" part of it) + @param applicationIdentifier Your application name for logging and storage purposes. + + After initialization, set it in the MSALCacheConfig class, e.g. + + MSALLegacySharedAccountsProvider *provider = [[MSALLegacySharedAccountsProvider alloc] initWithSharedKeychainAccessGroup:@"com.mycompany.mysso" + serviceIdentifier:@"MyAccountServiceIdentifier" + applicationIdentifier:@"MyApp"]; + + MSALPublicClientApplicationConfig *pcaConfig = [[MSALPublicClientApplicationConfig alloc] initWithClientId:clientId + redirectUri:redirectUri + authority:authority]; + + [pcaConfig.cacheConfig addExternalAccountProvider:provider]; + MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] initWithConfiguration:pcaConfig error:&error]; + + */ +- (instancetype)initWithSharedKeychainAccessGroup:(NSString *)sharedGroup + serviceIdentifier:(NSString *)serviceIdentifier + applicationIdentifier:(NSString *)applicationIdentifier; + +@end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/src/telemetry/MSALDefaultDispatcher.m b/MSAL/src/telemetry/MSALDefaultDispatcher.m deleted file mode 100644 index 2644525687..0000000000 --- a/MSAL/src/telemetry/MSALDefaultDispatcher.m +++ /dev/null @@ -1,145 +0,0 @@ -// 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 "MSALTelemetry.h" -#import "MSIDTelemetryEventInterface.h" -#import "MSALDefaultDispatcher.h" -#import "MSIDTelemetryEventInterface.h" -#import "MSIDTelemetryBaseEvent.h" -#import "MSALTelemetryDefaultEvent.h" -#import "MSIDTelemetryEventStrings.h" - -@interface MSALDefaultDispatcher () -{ - NSMutableDictionary* _objectsToBeDispatched; - id _dispatcher; - NSLock* _dispatchLock; - BOOL _setTelemetryOnFailure; - NSMutableArray *_errorEvents; - - MSALTelemetryDefaultEvent *_defaultEvent; -} -@end - -@implementation MSALDefaultDispatcher - -- (id)initWithDispatcher:(id)dispatcher setTelemetryOnFailure:(BOOL)setTelemetryOnFailure -{ - self = [super init]; - if (self) - { - _objectsToBeDispatched = [NSMutableDictionary new]; - _errorEvents = [NSMutableArray new]; - _dispatchLock = [NSLock new]; - - _dispatcher = dispatcher; - _setTelemetryOnFailure = setTelemetryOnFailure; - - _defaultEvent = [[MSALTelemetryDefaultEvent alloc] initWithName:MSID_TELEMETRY_EVENT_DEFAULT_EVENT context:nil]; - } - return self; -} - -- (BOOL)containsDispatcher:(id)dispatcher -{ - return _dispatcher == dispatcher; -} - -- (void)flush:(NSString *)requestId -{ - BOOL errorInEvent = [_errorEvents containsObject:requestId]; - - [_dispatchLock lock]; - // Remove requestId as we won't need it anymore - [_errorEvents removeObject:requestId]; - [_dispatchLock unlock]; - - if (_setTelemetryOnFailure && !errorInEvent) - { - return; - } - - [_dispatchLock lock]; //avoid access conflict when manipulating _objectsToBeDispatched - NSArray* events = [_objectsToBeDispatched objectForKey:requestId]; - [_objectsToBeDispatched removeObjectForKey:requestId]; - [_dispatchLock unlock]; - - if ([events count]) - { - NSArray* eventsToBeDispatched = @[[_defaultEvent getProperties]]; - [self dispatchEvents:[eventsToBeDispatched arrayByAddingObjectsFromArray:events]]; - } -} - -- (void)receive:(__unused NSString *)requestId - event:(id)event -{ - if ([NSString msidIsStringNilOrBlank:requestId] || !event) - { - return; - - } - - [_dispatchLock lock]; //make sure no one changes _objectsToBeDispatched while using it - NSMutableArray* eventsForRequestId = [_objectsToBeDispatched objectForKey:requestId]; - if (!eventsForRequestId) - { - eventsForRequestId = [NSMutableArray new]; - [_objectsToBeDispatched setObject:eventsForRequestId forKey:requestId]; - } - - [eventsForRequestId addObject:[event getProperties]]; - - if ([event errorInEvent]) - { - [_errorEvents addObject:requestId]; - } - - [_dispatchLock unlock]; -} - -- (void)dispatchEvents:(NSArray *> *)rawEvents; -{ - NSMutableArray *eventsToBeDispatched = [NSMutableArray new]; - - for (NSDictionary *event in rawEvents) - { - [eventsToBeDispatched addObject:[self appendPrefixForEvent:event]]; - } - - [_dispatcher dispatchEvent:eventsToBeDispatched]; -} - -- (NSDictionary *)appendPrefixForEvent:(NSDictionary *)event -{ - NSMutableDictionary *eventWithPrefix = [NSMutableDictionary new]; - - for (NSString *propertyName in [event allKeys]) - { - [eventWithPrefix setValue:event[propertyName] forKey:TELEMETRY_KEY(propertyName)]; - } - - return eventWithPrefix; -} - -@end diff --git a/MSAL/src/telemetry/MSALTelemetry.m b/MSAL/src/telemetry/MSALTelemetry.m index e4a49eb968..83fb5906af 100644 --- a/MSAL/src/telemetry/MSALTelemetry.m +++ b/MSAL/src/telemetry/MSALTelemetry.m @@ -37,30 +37,34 @@ + (MSALTelemetry *)sharedInstance return sharedInstance; } -- (void)addDispatcher:(nonnull id)dispatcher -setTelemetryOnFailure:(BOOL)setTelemetryOnFailure +- (BOOL)piiEnabled { - [MSALGlobalConfig.telemetryConfig addDispatcher:dispatcher setTelemetryOnFailure:setTelemetryOnFailure]; + return MSALGlobalConfig.telemetryConfig.piiEnabled; } -- (void)removeDispatcher:(nonnull id)dispatcher +- (void)setPiiEnabled:(BOOL)piiEnabled { - [MSALGlobalConfig.telemetryConfig removeDispatcher:dispatcher]; + MSALGlobalConfig.telemetryConfig.piiEnabled = piiEnabled; } -- (void)removeAllDispatchers +- (BOOL)notifyOnFailureOnly { - [MSALGlobalConfig.telemetryConfig removeAllDispatchers]; + return MSALGlobalConfig.telemetryConfig.notifyOnFailureOnly; } -- (BOOL)piiEnabled +- (void)setNotifyOnFailureOnly:(BOOL)notifyOnFailureOnly { - return MSALGlobalConfig.telemetryConfig.piiEnabled; + MSALGlobalConfig.telemetryConfig.notifyOnFailureOnly = notifyOnFailureOnly; } -- (void)setPiiEnabled:(BOOL)piiEnabled +- (MSALTelemetryCallback)telemetryCallback { - MSALGlobalConfig.telemetryConfig.piiEnabled = piiEnabled; + return MSALGlobalConfig.telemetryConfig.telemetryCallback; +} + +- (void)setTelemetryCallback:(MSALTelemetryCallback)telemetryCallback +{ + MSALGlobalConfig.telemetryConfig.telemetryCallback = telemetryCallback; } @end diff --git a/MSAL/src/telemetry/MSALTelemetryEventsObservingProxy.h b/MSAL/src/telemetry/MSALTelemetryEventsObservingProxy.h new file mode 100644 index 0000000000..25faf5a58d --- /dev/null +++ b/MSAL/src/telemetry/MSALTelemetryEventsObservingProxy.h @@ -0,0 +1,35 @@ +// 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 "MSIDTelemetryEventsObserving.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MSALTelemetryEventsObservingProxy : NSObject + +@property (nonatomic, copy, nullable) MSALTelemetryCallback telemetryCallback; + +@end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/src/telemetry/MSALTelemetryEventsObservingProxy.m b/MSAL/src/telemetry/MSALTelemetryEventsObservingProxy.m new file mode 100644 index 0000000000..20a5fb7ba5 --- /dev/null +++ b/MSAL/src/telemetry/MSALTelemetryEventsObservingProxy.m @@ -0,0 +1,39 @@ +// 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 "MSALTelemetryEventsObservingProxy.h" + +@implementation MSALTelemetryEventsObservingProxy + +#pragma mark - MSIDTelemetryEventsObserving + +- (void)onEventsReceived:(NSArray *> *)events +{ + NSDictionary *aggregatedEvent = [events firstObject]; + + if (!aggregatedEvent) return; + + if (self.telemetryCallback != nil) self.telemetryCallback(aggregatedEvent); +} + +@end diff --git a/MSAL/src/util/MSALRedirectUri+Internal.h b/MSAL/src/util/MSALRedirectUri+Internal.h index 835ddf9706..fe413663ab 100644 --- a/MSAL/src/util/MSALRedirectUri+Internal.h +++ b/MSAL/src/util/MSALRedirectUri+Internal.h @@ -35,6 +35,9 @@ - (nullable instancetype)initWithRedirectUri:(nonnull NSURL *)redirectUri brokerCapable:(BOOL)brokerCapable; ++ (nullable NSURL *)defaultNonBrokerRedirectUri:(nonnull NSString *)clientId; ++ (nullable NSURL *)defaultBrokerCapableRedirectUri; + @end #endif /* MSALRedirectUri_Internal_h */ diff --git a/MSAL/src/util/MSALRedirectUri.m b/MSAL/src/util/MSALRedirectUri.m index f707e0fe04..62300facde 100644 --- a/MSAL/src/util/MSALRedirectUri.m +++ b/MSAL/src/util/MSALRedirectUri.m @@ -52,4 +52,24 @@ - (id)copyWithZone:(NSZone *)zone return redirectUri; } +#pragma mark - Helpers + ++ (NSURL *)defaultNonBrokerRedirectUri:(NSString *)clientId +{ + if ([NSString msidIsStringNilOrBlank:clientId]) + { + return nil; + } + + NSString *redirectUri = [NSString stringWithFormat:@"msal%@://auth", clientId]; + return [NSURL URLWithString:redirectUri]; +} + ++ (NSURL *)defaultBrokerCapableRedirectUri +{ + NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier]; + NSString *redirectUri = [NSString stringWithFormat:@"msauth.%@://auth", bundleID]; + return [NSURL URLWithString:redirectUri]; +} + @end diff --git a/MSAL/src/util/MSALRedirectUriVerifier.h b/MSAL/src/util/MSALRedirectUriVerifier.h index 79d15a46ce..92d73be621 100644 --- a/MSAL/src/util/MSALRedirectUriVerifier.h +++ b/MSAL/src/util/MSALRedirectUriVerifier.h @@ -31,9 +31,6 @@ @interface MSALRedirectUriVerifier : NSObject -+ (NSURL *)defaultBrokerCapableRedirectUri; -+ (NSURL *)defaultNonBrokerRedirectUri:(NSString *)clientId; - + (MSALRedirectUri *)msalRedirectUriWithCustomUri:(NSString *)customRedirectUri clientId:(NSString *)clientId error:(NSError * __autoreleasing *)error; diff --git a/MSAL/src/util/ios/MSALRedirectUriVerifier.m b/MSAL/src/util/ios/MSALRedirectUriVerifier.m index 1d6df75219..d44a5693f4 100644 --- a/MSAL/src/util/ios/MSALRedirectUriVerifier.m +++ b/MSAL/src/util/ios/MSALRedirectUriVerifier.m @@ -64,7 +64,7 @@ + (MSALRedirectUri *)msalRedirectUriWithCustomUri:(NSString *)customRedirectUri } // First try to check for broker capable redirect URI - NSURL *defaultRedirectUri = [self defaultBrokerCapableRedirectUri]; + NSURL *defaultRedirectUri = [MSALRedirectUri defaultBrokerCapableRedirectUri]; NSError *redirectError = nil; if ([self verifySchemeIsRegistered:defaultRedirectUri error:&redirectError]) @@ -73,7 +73,7 @@ + (MSALRedirectUri *)msalRedirectUriWithCustomUri:(NSString *)customRedirectUri } // Now check the uri that is not broker capable for backward compat - defaultRedirectUri = [self defaultNonBrokerRedirectUri:clientId]; + defaultRedirectUri = [MSALRedirectUri defaultNonBrokerRedirectUri:clientId]; if ([self verifySchemeIsRegistered:defaultRedirectUri error:nil]) { @@ -88,27 +88,9 @@ + (MSALRedirectUri *)msalRedirectUriWithCustomUri:(NSString *)customRedirectUri return nil; } -+ (NSURL *)defaultNonBrokerRedirectUri:(NSString *)clientId -{ - if ([NSString msidIsStringNilOrBlank:clientId]) - { - return nil; - } - - NSString *redirectUri = [NSString stringWithFormat:@"msal%@://auth", clientId]; - return [NSURL URLWithString:redirectUri]; -} - -+ (NSURL *)defaultBrokerCapableRedirectUri -{ - NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier]; - NSString *redirectUri = [NSString stringWithFormat:@"msauth.%@://auth", bundleID]; - return [NSURL URLWithString:redirectUri]; -} - + (BOOL)redirectUriIsBrokerCapable:(NSURL *)redirectUri { - NSURL *defaultRedirectUri = [self defaultBrokerCapableRedirectUri]; + NSURL *defaultRedirectUri = [MSALRedirectUri defaultBrokerCapableRedirectUri]; // Check default MSAL format if ([defaultRedirectUri isEqual:redirectUri]) diff --git a/MSAL/src/util/mac/MSALRedirectUriVerifier.m b/MSAL/src/util/mac/MSALRedirectUriVerifier.m index 090ac6a8c1..b036b327b6 100644 --- a/MSAL/src/util/mac/MSALRedirectUriVerifier.m +++ b/MSAL/src/util/mac/MSALRedirectUriVerifier.m @@ -30,18 +30,6 @@ @implementation MSALRedirectUriVerifier -+ (NSURL *)defaultBrokerCapableRedirectUri -{ - return nil; -} - -+ (NSURL *)defaultNonBrokerRedirectUri:(NSString *)clientId -{ - NSString *scheme = [NSString stringWithFormat:@"msal%@", clientId]; - NSString *redirectUriString = [NSString stringWithFormat:@"%@://auth", scheme]; - return [NSURL URLWithString:redirectUriString]; -} - + (MSALRedirectUri *)msalRedirectUriWithCustomUri:(NSString *)customRedirectUri clientId:(NSString *)clientId error:(NSError * __autoreleasing *)error @@ -52,7 +40,7 @@ + (MSALRedirectUri *)msalRedirectUriWithCustomUri:(NSString *)customRedirectUri brokerCapable:NO]; } - return [[MSALRedirectUri alloc] initWithRedirectUri:[self defaultNonBrokerRedirectUri:clientId] + return [[MSALRedirectUri alloc] initWithRedirectUri:[MSALRedirectUri defaultBrokerCapableRedirectUri] brokerCapable:NO]; } diff --git a/MSAL/test/NSString+MSALTestUtil.m b/MSAL/test/NSString+MSALTestUtil.m index 2658d86d24..9df03d94c2 100644 --- a/MSAL/test/NSString+MSALTestUtil.m +++ b/MSAL/test/NSString+MSALTestUtil.m @@ -26,15 +26,13 @@ //------------------------------------------------------------------------------ #import "NSString+MSALTestUtil.h" -#import "MSALAuthorityFactory.h" @implementation NSString (MSALTestUtil) - (MSALAuthority *)msalAuthority { __auto_type authorityUrl = [[NSURL alloc] initWithString:self]; - __auto_type authority = [MSALAuthorityFactory authorityFromUrl:authorityUrl context:nil error:nil]; - + __auto_type authority = [MSALAuthority authorityWithURL:authorityUrl error:nil]; return authority; } diff --git a/MSAL/test/app/MSALTestAppSettings.h b/MSAL/test/app/MSALTestAppSettings.h index bf361983c7..ac33d8b024 100644 --- a/MSAL/test/app/MSALTestAppSettings.h +++ b/MSAL/test/app/MSALTestAppSettings.h @@ -34,10 +34,9 @@ extern NSString* MSALTestAppCacheChangeNotification; @interface MSALTestAppSettings : NSObject #define MSAL_APP_CLIENT_ID @"clientId" -#define MSAL_APP_PROFILE @"profile" +#define MSAL_APP_PROFILE @"currentProfile" #define MSAL_APP_REDIRECT_URI @"redirectUri" -@property (nonatomic) NSDictionary *profile; @property (nonatomic) MSALAuthority *authority; @property (nonatomic) MSALAccount *currentAccount; @property (nonatomic) NSString *loginHint; @@ -49,7 +48,12 @@ extern NSString* MSALTestAppCacheChangeNotification; + (NSArray *)b2cAuthorities; + (NSArray *)authorityTypes; + (NSArray *)availableScopes; + + (NSDictionary *)profiles; ++ (NSString *)currentProfileName; ++ (NSDictionary *)currentProfile; ++ (NSString *)profileTitleForIndex:(NSUInteger)index; +- (void)setCurrentProfile:(NSUInteger)index; - (BOOL)addScope:(NSString *)scope; - (BOOL)removeScope:(NSString *)scope; diff --git a/MSAL/test/app/MSALTestAppSettings.m b/MSAL/test/app/MSALTestAppSettings.m index edf9fe0c7d..16f78d40e7 100644 --- a/MSAL/test/app/MSALTestAppSettings.m +++ b/MSAL/test/app/MSALTestAppSettings.m @@ -24,7 +24,6 @@ #import "MSALTestAppSettings.h" #import "MSIDAuthority.h" #import "MSALAccountId.h" -#import "MSALAuthorityFactory.h" #import "MSIDAuthority.h" #import "MSALAuthority.h" #import "MSALAuthority_Internal.h" @@ -41,10 +40,7 @@ // github enlistment! static NSDictionary* _additionalProfiles() { - return @{ - @"MSAL-TestApp" : @{@"clientId" : @"b6c69a37-df96-4db0-9088-2ab96e1d8215", - @"redirectUri" :@"msauth.com.microsoft.MSALTestApp://auth"}, - }; + return nil; } #endif @@ -62,7 +58,11 @@ static NSArray *s_authorityTypes = nil; -static NSDictionary *s_profiles = nil; +static NSDictionary *s_additionalProfiles = nil; +static NSMutableDictionary *s_profiles = nil; +static NSArray* s_profileTitles = nil; +static NSUInteger s_currentProfileIdx = 0; +static NSDictionary *s_currentProfile = nil; @interface MSALTestAppSettings() { @@ -99,7 +99,20 @@ + (void)initialize s_b2cAuthorities = @[signinPolicyAuthority, signupPolicyAuthority, profilePolicyAuthority]; s_authorityTypes = @[@"AAD",@"B2C"]; - s_profiles = _additionalProfiles(); + + + NSString *defaultKey = @"MSAL-TestApp"; + NSDictionary *defaultValue = @{@"clientId" : @"b6c69a37-df96-4db0-9088-2ab96e1d8215", + @"redirectUri" :@"msauth.com.microsoft.MSALTestApp://auth"}; + + s_profiles = [[NSMutableDictionary alloc] initWithObjectsAndKeys:defaultValue, defaultKey, nil]; + s_additionalProfiles = _additionalProfiles(); + [s_profiles addEntriesFromDictionary:s_additionalProfiles]; + + NSMutableArray *titles = [[NSMutableArray alloc] init]; + [titles addObjectsFromArray:[s_profiles allKeys]]; + + s_profileTitles = titles; } + (MSALTestAppSettings*)settings @@ -109,7 +122,6 @@ + (MSALTestAppSettings*)settings dispatch_once(&s_settingsOnce,^{ s_settings = [MSALTestAppSettings new]; - s_settings->_profile = [[s_profiles allValues] objectAtIndex:0]; [s_settings readFromDefaults]; s_settings->_scopes = [NSMutableSet new]; }); @@ -117,11 +129,6 @@ + (MSALTestAppSettings*)settings return s_settings; } -+ (NSDictionary *)profiles -{ - return s_profiles; -} - + (NSArray *)aadAuthorities { return s_authorities; @@ -144,7 +151,7 @@ - (MSALAccount *)accountForAccountHomeIdentifier:(NSString *)accountIdentifier return nil; } - NSDictionary *currentProfile = _profile; + NSDictionary *currentProfile = [s_profiles objectForKey:[s_profileTitles objectAtIndex:s_currentProfileIdx]]; NSString *clientId = [currentProfile objectForKey:MSAL_APP_CLIENT_ID]; NSString *redirectUri = [currentProfile objectForKey:MSAL_APP_REDIRECT_URI]; @@ -158,33 +165,37 @@ - (MSALAccount *)accountForAccountHomeIdentifier:(NSString *)accountIdentifier if (application == nil) { - MSID_LOG_ERROR(nil, @"failed to create application to get user: %@", error); + MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"failed to create application to get user: %@", error); return nil; } - MSALAccount *account = [application accountForHomeAccountId:accountIdentifier error:&error]; + MSALAccount *account = [application accountForIdentifier:accountIdentifier error:&error]; return account; } - (void)readFromDefaults { + s_currentProfileIdx = 0; + s_currentProfile = [s_profiles objectForKey:[s_profileTitles objectAtIndex:s_currentProfileIdx]]; + NSDictionary *settings = [[NSUserDefaults standardUserDefaults] dictionaryForKey:MSAL_APP_SETTINGS_KEY]; if (!settings) { return; } - NSDictionary *profile = [settings objectForKey:MSAL_APP_PROFILE]; - if (profile) + NSString* currentProfile = [settings objectForKey:MSAL_APP_PROFILE]; + if (currentProfile) { - _profile = profile; + s_currentProfileIdx = [s_profileTitles indexOfObject:currentProfile]; + s_currentProfile = [s_profiles objectForKey:[s_profileTitles objectAtIndex:s_currentProfileIdx]]; } NSString *authorityString = [settings objectForKey:@"authority"]; if (authorityString) { NSURL *authorityUrl = [[NSURL alloc] initWithString:authorityString]; - __auto_type authority = [MSALAuthorityFactory authorityFromUrl:authorityUrl context:nil error:nil]; + __auto_type authority = [MSALAuthority authorityWithURL:authorityUrl error:nil]; _authority = authority; } @@ -230,7 +241,7 @@ - (void)setValidateAuthority:(BOOL)validateAuthority - (void)setCurrentAccount:(MSALAccount *)currentAccount { - [self setValue:currentAccount.homeAccountId.identifier forKey:@"currentHomeAccountId"]; + [self setValue:currentAccount.identifier forKey:@"currentHomeAccountId"]; _currentAccount = currentAccount; } @@ -266,10 +277,33 @@ - (BOOL)removeScope:(NSString *)scope return YES; } -- (void)setProfile:(id)profile ++ (NSDictionary *)profiles +{ + return s_profiles; +} + ++ (NSDictionary *)currentProfile { - [self setValue:profile forKey:MSAL_APP_PROFILE]; - _profile = profile; + return s_currentProfile; } ++ (NSString *)currentProfileName +{ + return [s_profileTitles objectAtIndex:s_currentProfileIdx]; +} + ++ (NSString *)profileTitleForIndex:(NSUInteger)index +{ + return [s_profileTitles objectAtIndex:index]; +} + +- (void)setCurrentProfile:(NSUInteger)index +{ + s_currentProfileIdx = index; + NSString *profileName = [s_profileTitles objectAtIndex:index]; + s_currentProfile = [s_profiles objectForKey:profileName]; + [self setValue:profileName forKey:MSAL_APP_PROFILE]; +} + + @end diff --git a/MSAL/test/app/ios/MSALTestAppAcquireTokenViewController.m b/MSAL/test/app/ios/MSALTestAppAcquireTokenViewController.m index d5b682cb57..6a5fa88c0f 100644 --- a/MSAL/test/app/ios/MSALTestAppAcquireTokenViewController.m +++ b/MSAL/test/app/ios/MSALTestAppAcquireTokenViewController.m @@ -43,8 +43,7 @@ #import "MSALInteractiveTokenParameters.h" #import "MSALSilentTokenParameters.h" #import "MSALAuthority.h" -#import -#import +#import #import "MSALHTTPConfig.h" #define TEST_EMBEDDED_WEBVIEW_TYPE_INDEX 0 @@ -457,7 +456,7 @@ - (void)updateResultViewError:(NSError *)error - (void)updateResultView:(MSALResult *)result { NSString *resultText = [NSString stringWithFormat:@"{\n\taccessToken = %@\n\texpiresOn = %@\n\ttenantId = %@\n\tuser = %@\n\tscopes = %@\n\tauthority = %@\n}", - [result.accessToken msidTokenHash], result.expiresOn, result.tenantId, result.account, result.scopes, result.authority]; + [result.accessToken msidTokenHash], result.expiresOn, result.tenantProfile.tenantId, result.account, result.scopes, result.authority]; [_resultView setText:resultText]; @@ -483,7 +482,7 @@ - (void)acquireTokenInteractive:(id)sender (void)sender; MSALTestAppSettings *settings = [MSALTestAppSettings settings]; - NSDictionary *currentProfile = [settings profile]; + NSDictionary *currentProfile = [MSALTestAppSettings currentProfile]; NSString *clientId = [currentProfile objectForKey:MSAL_APP_CLIENT_ID]; NSString *redirectUri = [currentProfile objectForKey:MSAL_APP_REDIRECT_URI]; MSALAuthority *authority = [settings authority]; @@ -586,7 +585,7 @@ - (IBAction)acquireTokenSilent:(id)sender return; } - NSDictionary *currentProfile = [settings profile]; + NSDictionary *currentProfile = [MSALTestAppSettings currentProfile]; NSString *clientId = [currentProfile objectForKey:MSAL_APP_CLIENT_ID]; NSString *redirectUri = [currentProfile objectForKey:MSAL_APP_REDIRECT_URI]; __auto_type authority = [settings authority]; @@ -655,7 +654,7 @@ - (IBAction)clearCache:(__unused id)sender MSALTestAppSettings *settings = [MSALTestAppSettings settings]; // Delete accounts. - NSDictionary *currentProfile = [settings profile]; + NSDictionary *currentProfile = [MSALTestAppSettings currentProfile]; NSString *clientId = [currentProfile objectForKey:MSAL_APP_CLIENT_ID]; NSString *redirectUri = [currentProfile objectForKey:MSAL_APP_REDIRECT_URI]; __auto_type authority = [settings authority]; @@ -784,7 +783,7 @@ - (void)runStressTestWithType:(MSALStressTestType)type return; } - NSDictionary *currentProfile = [settings profile]; + NSDictionary *currentProfile = [MSALTestAppSettings currentProfile]; NSString *clientId = [currentProfile objectForKey:MSAL_APP_CLIENT_ID]; NSString *redirectUri = [currentProfile objectForKey:MSAL_APP_REDIRECT_URI]; __auto_type authority = [settings authority]; diff --git a/MSAL/test/app/ios/MSALTestAppAuthorityViewController.m b/MSAL/test/app/ios/MSALTestAppAuthorityViewController.m index ce955f88f6..e95ea0b8e9 100644 --- a/MSAL/test/app/ios/MSALTestAppAuthorityViewController.m +++ b/MSAL/test/app/ios/MSALTestAppAuthorityViewController.m @@ -29,7 +29,6 @@ #import "MSALTestAppSettings.h" #import "MSALAuthority.h" #import "MSIDAuthority.h" -#import "MSALAuthorityFactory.h" #import "MSALAuthority_Internal.h" @interface MSALTestAppAuthorityViewController () @@ -159,7 +158,8 @@ - (void)rowSelected:(NSInteger)row } else { - MSALAuthority *authority = [MSALAuthorityFactory authorityFromUrl:[NSURL URLWithString:_authorities[row - 1]] context:nil error:nil]; + NSURL *authorityURL = [NSURL URLWithString:_authorities[row - 1]]; + MSALAuthority *authority = [MSALAuthority authorityWithURL:authorityURL error:nil]; settings.authority = authority; } } diff --git a/MSAL/test/app/ios/MSALTestAppCacheViewController.m b/MSAL/test/app/ios/MSALTestAppCacheViewController.m index 73eb7a8b5e..7effb7f3ea 100644 --- a/MSAL/test/app/ios/MSALTestAppCacheViewController.m +++ b/MSAL/test/app/ios/MSALTestAppCacheViewController.m @@ -347,12 +347,12 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N if ([token isKindOfClass:[MSIDLegacyRefreshToken class]]) { - cell.textLabel.text = [NSString stringWithFormat:@"[Legacy RT] %@, FRT %@", token.authority.url.msidTenant, refreshToken.clientId]; + cell.textLabel.text = [NSString stringWithFormat:@"[Legacy RT] %@, FRT %@", token.realm, refreshToken.clientId]; cell.detailTextLabel.text = [NSString stringWithFormat:@"[ClientId] %@", refreshToken.clientId]; } else { - cell.textLabel.text = [NSString stringWithFormat:@"[RT] %@, FRT %@", refreshToken.authority.url.msidTenant, refreshToken.familyId]; + cell.textLabel.text = [NSString stringWithFormat:@"[RT] %@, FRT %@", refreshToken.realm, refreshToken.familyId]; cell.detailTextLabel.text = [NSString stringWithFormat:@"[ClientId] %@", refreshToken.clientId]; } @@ -366,7 +366,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N case MSIDAccessTokenType: { MSIDAccessToken *accessToken = (MSIDAccessToken *) token; - cell.textLabel.text = [NSString stringWithFormat:@"[AT] %@/%@", [accessToken.scopes msidToString], accessToken.authority.url.msidTenant]; + cell.textLabel.text = [NSString stringWithFormat:@"[AT] %@/%@", [accessToken.scopes msidToString], accessToken.realm]; cell.detailTextLabel.text = [NSString stringWithFormat:@"[ClientId] %@", accessToken.clientId]; if (accessToken.isExpired) { @@ -376,7 +376,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } case MSIDIDTokenType: { - cell.textLabel.text = [NSString stringWithFormat:@"[ID] %@", token.authority.url.msidTenant]; + cell.textLabel.text = [NSString stringWithFormat:@"[ID] %@", token.realm]; cell.detailTextLabel.text = [NSString stringWithFormat:@"[ClientId] %@", token.clientId]; break; } @@ -393,7 +393,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N else if([cacheEntry isKindOfClass:[MSIDAccount class]]) { MSIDAccount *account = (MSIDAccount *)cacheEntry; - cell.textLabel.text = [NSString stringWithFormat:@"[AC] %@", account.authority.environment]; + cell.textLabel.text = [NSString stringWithFormat:@"[AC] %@", account.environment]; cell.detailTextLabel.text = [NSString stringWithFormat:@"[Account Identifier] %@", [self rowIdentifier:account.accountIdentifier]]; } diff --git a/MSAL/test/app/ios/MSALTestAppProfileViewController.m b/MSAL/test/app/ios/MSALTestAppProfileViewController.m index 6573c9ab85..dd49eeb8a9 100644 --- a/MSAL/test/app/ios/MSALTestAppProfileViewController.m +++ b/MSAL/test/app/ios/MSALTestAppProfileViewController.m @@ -72,29 +72,18 @@ - (NSInteger)numberOfRows - (NSString *)labelForRow:(NSInteger)row { - NSArray *keys = [_profiles allKeys]; - return keys[row]; + return [MSALTestAppSettings profileTitleForIndex:row]; } - (void)rowSelected:(NSInteger)row { MSALTestAppSettings *settings = [MSALTestAppSettings settings]; - NSString* profile = [[_profiles allKeys] objectAtIndex:row]; - settings.profile = [_profiles objectForKey:profile]; + [settings setCurrentProfile:row]; } + (NSString *)currentTitle { - NSDictionary* currentProfile = [[MSALTestAppSettings settings] profile]; - NSArray *profiles = [[MSALTestAppSettings profiles] allKeysForObject:currentProfile]; - if (profiles.count != 0) - { - return [profiles firstObject]; - } - else - { - return [[[MSALTestAppSettings profiles] allKeys] objectAtIndex:0]; - } + return [MSALTestAppSettings currentProfileName]; } @end diff --git a/MSAL/test/app/ios/MSALTestAppSettingsViewController.m b/MSAL/test/app/ios/MSALTestAppSettingsViewController.m index 5f8c947dc4..e1057b83ed 100644 --- a/MSAL/test/app/ios/MSALTestAppSettingsViewController.m +++ b/MSAL/test/app/ios/MSALTestAppSettingsViewController.m @@ -95,7 +95,7 @@ - (id)init _keychainId = teamId ? teamId : @"";*/ MSALTestAppSettingsRow* clientIdRow = [MSALTestAppSettingsRow rowWithTitle:@"clientId"]; - NSDictionary *currentProfile = [[MSALTestAppSettings settings] profile]; + NSDictionary *currentProfile = [MSALTestAppSettings currentProfile]; NSString *clientId = [currentProfile objectForKey:MSAL_APP_CLIENT_ID]; clientIdRow.valueBlock = ^NSString *{ return clientId; }; MSALTestAppSettingsRow* authorityRow = [MSALTestAppSettingsRow rowWithTitle:@"authority"]; @@ -250,4 +250,6 @@ - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexP } } + + @end diff --git a/MSAL/test/app/ios/MSALTestAppTelemetryViewController.m b/MSAL/test/app/ios/MSALTestAppTelemetryViewController.m index a17633fce7..917a06a10d 100644 --- a/MSAL/test/app/ios/MSALTestAppTelemetryViewController.m +++ b/MSAL/test/app/ios/MSALTestAppTelemetryViewController.m @@ -26,8 +26,8 @@ //------------------------------------------------------------------------------ #import "MSALTestAppTelemetryViewController.h" -#import "MSALTestAppTelemetryDispatcher.h" #import "MSIDTelemetryEventStrings.h" +#import "MSALTelemetry.h" #import #import @@ -69,28 +69,22 @@ - (id)init return self; } -#pragma mark - #pragma mark - Tracking - (void)startTracking { - MSALTestAppTelemetryDispatcher *dispatcher = [MSALTestAppTelemetryDispatcher new]; - - [dispatcher setDispatcherCallback:^(NSArray *> *events) - { - [_telemetryEvents addObjectsFromArray:events]; - [self refresh]; - }]; - - [MSALGlobalConfig.telemetryConfig addDispatcher:dispatcher setTelemetryOnFailure:NO]; + MSALGlobalConfig.telemetryConfig.telemetryCallback = ^(NSDictionary *event) + { + [_telemetryEvents addObject:event]; + [self refresh]; + }; } - (void)stopTracking { - [MSALGlobalConfig.telemetryConfig removeAllDispatchers]; + MSALGlobalConfig.telemetryConfig.telemetryCallback = nil; } -#pragma mark - #pragma mark - UI Lifecycle - (void)viewDidLoad @@ -106,13 +100,12 @@ - (void)viewDidLoad - (void)viewWillAppear:(BOOL)animated { - (void)animated; - self.navigationController.navigationBarHidden = NO; [super viewWillAppear:animated]; + + self.navigationController.navigationBarHidden = NO; } -#pragma mark - -#pragma mark Methods for subclasses to override +#pragma mark - Methods for subclasses to override - (void)refresh { @@ -139,8 +132,7 @@ - (NSString *)labelForRow:(NSInteger)row } } -#pragma mark - -#pragma mark UITableViewDelegate +#pragma mark - UITableViewDelegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { @@ -158,7 +150,6 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath [self refresh]; } -#pragma mark - #pragma mark - Actions - (IBAction)clearTelemetry:(id)sender @@ -169,7 +160,6 @@ - (IBAction)clearTelemetry:(id)sender [self refresh]; } -#pragma mark - #pragma mark - Helpers - (NSString *)eventAsShortString:(NSDictionary *)telemetryEvent diff --git a/MSAL/test/app/ios/MSALTestAppUserViewController.m b/MSAL/test/app/ios/MSALTestAppUserViewController.m index b3ff4aa654..f753772249 100644 --- a/MSAL/test/app/ios/MSALTestAppUserViewController.m +++ b/MSAL/test/app/ios/MSALTestAppUserViewController.m @@ -29,7 +29,6 @@ #import "MSALPublicClientApplication.h" #import "MSALTestAppSettings.h" #import "MSALAccountId.h" -#import "MSIDAuthorityFactory.h" #import "MSALAccount.h" @interface MSALTestAppUserViewController () @@ -67,7 +66,7 @@ - (void)refresh _accounts = nil; MSALTestAppSettings *settings = [MSALTestAppSettings settings]; - NSDictionary *currentProfile = [settings profile]; + NSDictionary *currentProfile = [MSALTestAppSettings currentProfile]; NSString *clientId = [currentProfile objectForKey:MSAL_APP_CLIENT_ID]; NSString *redirectUri = [currentProfile objectForKey:MSAL_APP_REDIRECT_URI]; MSALAuthority *authority = [settings authority]; @@ -76,12 +75,12 @@ - (void)refresh MSALPublicClientApplicationConfig *pcaConfig = [[MSALPublicClientApplicationConfig alloc] initWithClientId:clientId redirectUri:redirectUri authority:authority]; - + MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] initWithConfiguration:pcaConfig error:&error]; if (!application) { - MSID_LOG_ERROR(nil, @"Failed to create public client application: %@", error); + MSID_LOG_WITH_CTX(MSIDLogLevelError, nil, @"Failed to create public client application: %@", error); return; } @@ -135,11 +134,11 @@ - (NSInteger)currentRow return 0; } - NSString *currentAccountId = currentAccount.homeAccountId.identifier; + NSString *currentAccountId = currentAccount.identifier; for (NSInteger i = 0; i < _accounts.count; i++) { - if ([currentAccountId isEqualToString:_accounts[i].homeAccountId.identifier]) + if ([currentAccountId isEqualToString:_accounts[i].identifier]) { return i + 1; } diff --git a/MSAL/test/app/mac/resources/Assets.xcassets/AppIcon.appiconset/Contents.json b/MSAL/test/app/mac/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from MSAL/test/app/mac/resources/Assets.xcassets/AppIcon.appiconset/Contents.json rename to MSAL/test/app/mac/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/MSAL/test/app/mac/Assets.xcassets/Contents.json b/MSAL/test/app/mac/Assets.xcassets/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/MSAL/test/app/mac/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MSAL/test/app/mac/Base.lproj/Main.storyboard b/MSAL/test/app/mac/Base.lproj/Main.storyboard new file mode 100644 index 0000000000..fab9e0117b --- /dev/null +++ b/MSAL/test/app/mac/Base.lproj/Main.storyboard @@ -0,0 +1,1473 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MSAL/test/app/mac/resources/Info.plist b/MSAL/test/app/mac/Info.plist similarity index 84% rename from MSAL/test/app/mac/resources/Info.plist rename to MSAL/test/app/mac/Info.plist index 35eb1a738e..f358448e86 100644 --- a/MSAL/test/app/mac/resources/Info.plist +++ b/MSAL/test/app/mac/Info.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - en + $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIconFile @@ -23,9 +23,9 @@ LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright - Copyright © 2017 Microsoft. All rights reserved. - NSMainNibFile - MainMenu + Copyright © 2019 Microsoft. All rights reserved. + NSMainStoryboardFile + Main NSPrincipalClass NSApplication diff --git a/MSAL/test/app/mac/MSALAcquireTokenViewController.h b/MSAL/test/app/mac/MSALAcquireTokenViewController.h new file mode 100644 index 0000000000..da29d1a5c3 --- /dev/null +++ b/MSAL/test/app/mac/MSALAcquireTokenViewController.h @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALScopesViewController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MSALAcquireTokenViewController : NSViewController + +@end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/test/app/mac/MSALAcquireTokenViewController.m b/MSAL/test/app/mac/MSALAcquireTokenViewController.m new file mode 100644 index 0000000000..7813fc2348 --- /dev/null +++ b/MSAL/test/app/mac/MSALAcquireTokenViewController.m @@ -0,0 +1,397 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALAcquireTokenViewController.h" +#import +#import "MSALTestAppSettings.h" +#import "MSALScopesViewController.h" +#import "MSALInteractiveTokenParameters.h" +#import "MSALPublicClientApplication+Internal.h" +#import "MSIDDefaultTokenCacheAccessor.h" +#import "MSALSilentTokenParameters.h" +#import "WebKit/WebKit.h" + +static NSString * const clientId = @"clientId"; +static NSString * const redirectUri = @"redirectUri"; +static NSString * const defaultScope = @"User.Read"; + +@interface MSALAcquireTokenViewController () + +@property (weak) IBOutlet NSPopUpButton *profilesPopUp; +@property (weak) IBOutlet NSTextField *clientIdTextField; +@property (weak) IBOutlet NSTextField *redirectUriTextField; +@property (weak) IBOutlet NSTextField *scopesTextField; +@property (weak) IBOutlet NSSegmentedControl *promptSegment; +@property (weak) IBOutlet NSTextField *loginHintTextField; +@property (weak) IBOutlet NSTextView *resultTextView; +@property (weak) IBOutlet NSTextField *extraQueryParamsTextField; +@property (weak) IBOutlet NSSegmentedControl *webViewSegment; +@property (weak) IBOutlet NSSegmentedControl *validateAuthoritySegment; +@property (weak) IBOutlet NSStackView *acquireTokenView; +@property (weak) IBOutlet WKWebView *webView; +@property (weak) IBOutlet NSPopUpButton *userPopup; + + +@property MSALTestAppSettings *settings; +@property NSArray *selectedScopes; +@property NSArray *accounts; + +@end + +@implementation MSALAcquireTokenViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.settings = [MSALTestAppSettings settings]; + [self populateProfiles]; + [self populateUsers]; + self.selectedScopes = @[defaultScope]; + self.validateAuthoritySegment.selectedSegment = self.settings.validateAuthority ? 0 : 1; +} + +- (void)populateProfiles +{ + [self.profilesPopUp removeAllItems]; + [self.profilesPopUp addItemsWithTitles:[[MSALTestAppSettings profiles] allKeys]]; + [self.profilesPopUp selectItemWithTitle:[MSALTestAppSettings currentProfileName]]; + self.clientIdTextField.stringValue = [[MSALTestAppSettings currentProfile] objectForKey:clientId]; + self.redirectUriTextField.stringValue = [[MSALTestAppSettings currentProfile] objectForKey:redirectUri]; +} + +- (void)populateUsers +{ + NSError *error = nil; + MSALPublicClientApplication *application = [self createPublicClientApplication:&error]; + [self.userPopup removeAllItems]; + + if (application && !error) + { + self.accounts = [application allAccounts:&error]; + + for (MSALAccount *account in self.accounts) + { + [self.userPopup addItemWithTitle:account.username]; + } + } +} + +- (IBAction)selectedProfileChanged:(id)sender +{ + [self.settings setCurrentProfile:[self.profilesPopUp indexOfSelectedItem]]; + self.clientIdTextField.stringValue = [[MSALTestAppSettings currentProfile] objectForKey:clientId]; + self.redirectUriTextField.stringValue = [[MSALTestAppSettings currentProfile] objectForKey:redirectUri]; +} + +- (void)prepareForSegue:(NSStoryboardSegue *)segue sender:(id)sender +{ + if ([segue.identifier isEqualToString:@"addScopesSegue"]) + { + MSALScopesViewController *scopesController = (MSALScopesViewController *)segue.destinationController; + scopesController.delegate = self; + } +} + +- (void)setScopes:(NSArray *)scopes +{ + if ([scopes count]) + { + NSString *selectedScopes = [scopes componentsJoinedByString:@","]; + [self.scopesTextField setStringValue:selectedScopes]; + self.selectedScopes = scopes; + } + else + { + [self.scopesTextField setStringValue:defaultScope]; + self.selectedScopes = @[defaultScope]; + } +} + +- (void)updateResultView:(MSALResult *)result +{ + NSString *resultText = [NSString stringWithFormat:@"{\n\taccessToken = %@\n\texpiresOn = %@\n\ttenantId = %@\n\tuser = %@\n\tscopes = %@\n\tauthority = %@\n}", + [result.accessToken msidTokenHash], result.expiresOn, result.tenantProfile.tenantId, result.account, result.scopes, result.authority]; + + [self.resultTextView setString:resultText]; + + NSLog(@"%@", resultText); +} + +- (void)updateResultViewError:(NSError *)error +{ + NSString *resultText = [NSString stringWithFormat:@"%@", error]; + [self.resultTextView setString:resultText]; + NSLog(@"%@", resultText); +} + +- (MSALPromptType)promptType +{ + NSString *promptType = [self.promptSegment labelForSegment:[self.promptSegment selectedSegment]]; + + if ([promptType isEqualToString:@"Select"]) + return MSALPromptTypeSelectAccount; + if ([promptType isEqualToString:@"Login"]) + return MSALPromptTypeLogin; + if ([promptType isEqualToString:@"Consent"]) + return MSALPromptTypeConsent; + + @throw @"Do not recognize prompt behavior"; +} + +- (BOOL)passedInWebview +{ + NSString* webViewType = [self.webViewSegment labelForSegment:[self.webViewSegment selectedSegment]]; + + if ([webViewType isEqualToString:@"MSAL"]) + { + return NO; + } + else if ([webViewType isEqualToString:@"Passed In"]) + { + return YES; + } + else + { + @throw @"unexpected webview type"; + } +} + +- (void)showAlert:(NSString *)messageText informativeText:(NSString *)informativeText +{ + dispatch_async(dispatch_get_main_queue(), ^{ + NSAlert *alert = [[NSAlert alloc] init]; + alert.messageText = messageText; + [alert addButtonWithTitle:@"OK"]; + alert.informativeText = informativeText; + [alert runModal]; + }); +} + +- (IBAction)clearCache:(id)sender +{ + MSALTestAppSettings *settings = [MSALTestAppSettings settings]; + + // Delete accounts. + NSDictionary *currentProfile = [MSALTestAppSettings currentProfile]; + NSString *clientId = [currentProfile objectForKey:MSAL_APP_CLIENT_ID]; + NSString *redirectUri = [currentProfile objectForKey:MSAL_APP_REDIRECT_URI]; + __auto_type authority = [settings authority]; + + NSError *error = nil; + MSALPublicClientApplicationConfig *pcaConfig = [[MSALPublicClientApplicationConfig alloc] initWithClientId:clientId + redirectUri:redirectUri + authority:authority]; + if (self.validateAuthoritySegment.selectedSegment == 1) + { + pcaConfig.knownAuthorities = @[pcaConfig.authority]; + } + + MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] initWithConfiguration:pcaConfig error:&error]; + + if (!application) + { + NSString *resultText = [NSString stringWithFormat:@"Failed to create PublicClientApplication:\n%@", error]; + [self.resultTextView setString:resultText]; + return; + } + + BOOL result = [application.tokenCache clearWithContext:nil error:&error]; + + if (result) + { + [self.resultTextView setString:@"Successfully cleared cache."]; + settings.currentAccount = nil; + + [[NSNotificationCenter defaultCenter] postNotificationName:MSALTestAppCacheChangeNotification object:self]; + } + else + { + [self.resultTextView setString:[NSString stringWithFormat:@"Failed to clear cache, error = %@", error]]; + } +} + +- (IBAction)clearCookies:(id)sender +{ + // Clear WKWebView cookies + if (@available(macOS 10.11, *)) { + NSSet *allTypes = [WKWebsiteDataStore allWebsiteDataTypes]; + [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:allTypes + modifiedSince:[NSDate dateWithTimeIntervalSince1970:0] + completionHandler:^{}]; + + [_resultTextView setString:[NSString stringWithFormat:@"Successfully Cleared cookies."]]; + } +} + +- (MSALPublicClientApplication *)createPublicClientApplication:(NSError * _Nullable __autoreleasing * _Nullable)error +{ + NSDictionary *currentProfile = [MSALTestAppSettings currentProfile]; + NSString *clientId = [currentProfile objectForKey:MSAL_APP_CLIENT_ID]; + NSString *redirectUri = [currentProfile objectForKey:MSAL_APP_REDIRECT_URI]; + MSALAuthority *authority = [self.settings authority]; + + MSALPublicClientApplicationConfig *pcaConfig = [[MSALPublicClientApplicationConfig alloc] initWithClientId:clientId + redirectUri:redirectUri + authority:authority]; + if (self.validateAuthoritySegment.selectedSegment == 1) + { + pcaConfig.knownAuthorities = @[pcaConfig.authority]; + } + + MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] initWithConfiguration:pcaConfig error:error]; + + return application; +} + +- (IBAction)acquireTokenInteractive:(id)sender +{ + (void)sender; + + NSError *error = nil; + MSALPublicClientApplication *application = [self createPublicClientApplication:&error]; + + if (!application || error) + { + NSString *resultText = [NSString stringWithFormat:@"Failed to create PublicClientApplication:\n%@", error]; + [self.resultTextView setString:resultText]; + return; + } + + __block BOOL fBlockHit = NO; + + void (^completionBlock)(MSALResult *result, NSError *error) = ^(MSALResult *result, NSError *error) { + + if (fBlockHit) + { + [self showAlert:@"Error!" informativeText:@"Completion block was hit multiple times!"]; + return; + } + fBlockHit = YES; + + dispatch_async(dispatch_get_main_queue(), ^{ + + if (result) + { + [self updateResultView:result]; + [self populateUsers]; + } + else + { + [self updateResultViewError:error]; + } + + [self.webView setHidden:YES]; + [self.acquireTokenView setHidden:NO]; + + [[NSNotificationCenter defaultCenter] postNotificationName:MSALTestAppCacheChangeNotification object:self]; + }); + }; + + if ([self passedInWebview]) + { + application.customWebview = self.webView; + [self.acquireTokenView setHidden:YES]; + [self.webView setHidden:NO]; + } + + NSDictionary *extraQueryParameters = [NSDictionary msidDictionaryFromWWWFormURLEncodedString:[self.extraQueryParamsTextField stringValue]]; + MSALInteractiveTokenParameters *parameters = [[MSALInteractiveTokenParameters alloc] initWithScopes:self.selectedScopes]; + parameters.loginHint = [self.loginHintTextField stringValue]; + parameters.account = self.settings.currentAccount; + parameters.promptType = [self promptType]; + parameters.extraQueryParameters = extraQueryParameters; + + [application acquireTokenWithParameters:parameters completionBlock:completionBlock]; + +} + +- (IBAction)acquireTokenSilent:(id)sender +{ + (void)sender; + NSError *error = nil; + MSALPublicClientApplication *application = [self createPublicClientApplication:&error]; + if (!application || error) + { + NSString *resultText = [NSString stringWithFormat:@"Failed to create PublicClientApplication:\n%@", error]; + [self.resultTextView setString:resultText]; + return; + } + + __block BOOL fBlockHit = NO; + + NSString *userName = [self.userPopup titleOfSelectedItem]; + MSALAccount *currentAccount = nil; + + if (!self.accounts) + { + self.accounts = [application allAccounts:nil]; + } + + for (MSALAccount *account in self.accounts) + { + if ([account.username isEqualToString:userName]) + { + currentAccount = account; + } + } + + if (!currentAccount) + { + [self showAlert:@"Error!" informativeText:@"User needs to be selected for acquire token silent call"]; + return; + } + + MSALSilentTokenParameters *parameters = [[MSALSilentTokenParameters alloc] initWithScopes:self.selectedScopes account:currentAccount]; + parameters.authority = self.settings.authority; + + [application acquireTokenSilentWithParameters:parameters completionBlock:^(MSALResult *result, NSError *error) + { + if (fBlockHit) + { + dispatch_async(dispatch_get_main_queue(), ^{ + [self showAlert:@"Error!" informativeText:@"Completion block was hit multiple times!"]; + }); + + return; + } + fBlockHit = YES; + + dispatch_async(dispatch_get_main_queue(), ^{ + if (result) + { + [self updateResultView:result]; + } + else + { + [self updateResultViewError:error]; + } + [[NSNotificationCenter defaultCenter] postNotificationName:MSALTestAppCacheChangeNotification object:self]; + }); + }]; +} + + +@end diff --git a/MSAL/test/app/mac/MSALAppDelegate.h b/MSAL/test/app/mac/MSALAppDelegate.h new file mode 100644 index 0000000000..b7afa6822d --- /dev/null +++ b/MSAL/test/app/mac/MSALAppDelegate.h @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +// +// 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 + +@interface MSALAppDelegate : NSObject + +@end + diff --git a/MSAL/test/app/mac/MSALAppDelegate.m b/MSAL/test/app/mac/MSALAppDelegate.m new file mode 100644 index 0000000000..46ab44f271 --- /dev/null +++ b/MSAL/test/app/mac/MSALAppDelegate.m @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALAppDelegate.h" + +@interface MSALAppDelegate () + +@end + +@implementation MSALAppDelegate + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { + // Insert code here to initialize your application +} + + +- (void)applicationWillTerminate:(NSNotification *)aNotification { + // Insert code here to tear down your application +} + +@end diff --git a/MSAL/test/app/mac/MSALCacheViewController.h b/MSAL/test/app/mac/MSALCacheViewController.h new file mode 100644 index 0000000000..2004f5699d --- /dev/null +++ b/MSAL/test/app/mac/MSALCacheViewController.h @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// +// 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 + +NS_ASSUME_NONNULL_BEGIN + +@interface MSALCacheViewController : NSViewController + +@end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/test/unit/MSALTelemetryTestDispatcher.m b/MSAL/test/app/mac/MSALCacheViewController.m similarity index 84% rename from MSAL/test/unit/MSALTelemetryTestDispatcher.m rename to MSAL/test/app/mac/MSALCacheViewController.m index ea6afc7991..75159ca39d 100644 --- a/MSAL/test/unit/MSALTelemetryTestDispatcher.m +++ b/MSAL/test/app/mac/MSALCacheViewController.m @@ -25,17 +25,17 @@ // //------------------------------------------------------------------------------ -#import "MSALTelemetryTestDispatcher.h" +#import "MSALCacheViewController.h" -@implementation MSALTelemetryTestDispatcher +@interface MSALCacheViewController () -- (void)dispatchEvent:(nonnull NSArray *> *)events -{ - if (_dispatcherCallback) - { - _dispatcherCallback(events); - } -} +@end +@implementation MSALCacheViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do view setup here. +} @end diff --git a/MSAL/test/app/mac/MSALMacTestApp.entitlements b/MSAL/test/app/mac/MSALMacTestApp.entitlements new file mode 100644 index 0000000000..625af03d99 --- /dev/null +++ b/MSAL/test/app/mac/MSALMacTestApp.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.files.user-selected.read-only + + com.apple.security.network.client + + + diff --git a/MSAL/test/app/mac/MSALScopesViewController.h b/MSAL/test/app/mac/MSALScopesViewController.h new file mode 100644 index 0000000000..a9cef37bb5 --- /dev/null +++ b/MSAL/test/app/mac/MSALScopesViewController.h @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------------ +// +// 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 + +NS_ASSUME_NONNULL_BEGIN + +@protocol MSALScopesDelegate +- (void)setScopes:(NSArray *)scopes; +@end + +@interface MSALScopesViewController : NSViewController + +@property (weak) id delegate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/MSAL/test/app/mac/MSALScopesViewController.m b/MSAL/test/app/mac/MSALScopesViewController.m new file mode 100644 index 0000000000..9b599f4536 --- /dev/null +++ b/MSAL/test/app/mac/MSALScopesViewController.m @@ -0,0 +1,102 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALScopesViewController.h" +#import "MSALTestAppSettings.h" + +@interface MSALScopesViewController () +@property NSMutableArray *scopesList; +@property (weak) IBOutlet NSTableView *scopesView; +@property (weak) IBOutlet NSTextField *scopesText; + +@end + +@implementation MSALScopesViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do view setup here. + self.scopesView.delegate = self; + self.scopesView.dataSource = self; + [self.scopesView setAllowsMultipleSelection: YES]; + self.scopesList = [[NSMutableArray alloc] init]; + [self.scopesList addObjectsFromArray:[MSALTestAppSettings availableScopes]]; + [self.scopesView reloadData]; +} + +- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView +{ + return [self.scopesList count]; +} + +- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row +{ + NSString *scope = [self.scopesList objectAtIndex:row]; + NSString *identifier = [tableColumn identifier]; + if ([identifier isEqualToString:@"ScopesCell"]) + { + NSTableCellView *cellView = [tableView makeViewWithIdentifier:identifier owner:self]; + [cellView.textField setStringValue:scope]; + return cellView; + } + return nil; +} + +- (IBAction)insertNewRow:(id)sender +{ + NSString *scope = [self.scopesText stringValue]; + + if (scope.length > 0 && ![self.scopesList containsObject:scope]) + { + NSInteger selectedRow = [self.scopesView selectedRow]; + selectedRow++; + [self.scopesList insertObject:scope atIndex:selectedRow]; + [self.scopesView beginUpdates]; + [self.scopesView insertRowsAtIndexes:[NSIndexSet indexSetWithIndex:selectedRow] withAnimation:NSTableViewAnimationEffectGap]; + [self.scopesView scrollRowToVisible:selectedRow]; + [self.scopesView endUpdates]; + } +} + +- (IBAction)deleteSelectedRows:(id)sender +{ + NSIndexSet *indexes = [self.scopesView selectedRowIndexes]; + [self.scopesList removeObjectsAtIndexes:indexes]; + [self.scopesView removeRowsAtIndexes:indexes withAnimation:NSTableViewAnimationSlideDown]; +} + +- (IBAction)done:(id)sender +{ + NSIndexSet *indexes = [self.scopesView selectedRowIndexes]; + NSMutableArray *selectedScopes = [[NSMutableArray alloc] init]; + [selectedScopes addObjectsFromArray:[self.scopesList objectsAtIndexes:indexes]]; + [self.delegate setScopes:selectedScopes]; + [self dismissViewController:self]; +} + + +@end diff --git a/MSAL/test/app/mac/resources/Base.lproj/MainMenu.xib b/MSAL/test/app/mac/resources/Base.lproj/MainMenu.xib deleted file mode 100644 index 0dd3d97ee2..0000000000 --- a/MSAL/test/app/mac/resources/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,692 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MSAL/test/automation/ios/actions/MSALAutomationAcquireTokenAction.m b/MSAL/test/automation/ios/actions/MSALAutomationAcquireTokenAction.m index 5afa0da31e..1ec4168fa6 100644 --- a/MSAL/test/automation/ios/actions/MSALAutomationAcquireTokenAction.m +++ b/MSAL/test/automation/ios/actions/MSALAutomationAcquireTokenAction.m @@ -116,6 +116,10 @@ - (void)performActionWithParameters:(MSIDAutomationTestRequest *)testRequest { promptType = MSALPromptTypePromptIfNecessary; } + else if ([testRequest.promptBehavior isEqualToString:@"select_account"]) + { + promptType = MSALPromptTypeSelectAccount; + } MSALAuthority *acquireTokenAuthority = nil; diff --git a/MSAL/test/automation/ios/actions/MSALAutomationBaseAction.m b/MSAL/test/automation/ios/actions/MSALAutomationBaseAction.m index 3d7185b680..a493045998 100644 --- a/MSAL/test/automation/ios/actions/MSALAutomationBaseAction.m +++ b/MSAL/test/automation/ios/actions/MSALAutomationBaseAction.m @@ -27,7 +27,6 @@ #import "MSALAutomationBaseAction.h" #import -#import "MSALAuthorityFactory.h" #import "MSIDAutomationTestRequest.h" #import "MSIDLegacyTokenCacheAccessor.h" #import "MSIDDefaultTokenCacheAccessor.h" @@ -39,6 +38,7 @@ #import "MSIDAutomationSuccessResult.h" #import "MSALAccount.h" #import "MSALAccount+Internal.h" +#import "MSALTenantProfile.h" #import "MSALSliceConfig.h" @implementation MSALAutomationBaseAction @@ -90,7 +90,7 @@ - (MSALPublicClientApplication *)applicationWithParameters:(MSIDAutomationTestRe if (parameters.configurationAuthority) { NSURL *authorityUrl = [[NSURL alloc] initWithString:parameters.configurationAuthority]; - authority = [MSALAuthorityFactory authorityFromUrl:authorityUrl context:nil error:nil]; + authority = [MSALAuthority authorityWithURL:authorityUrl error:nil]; } @@ -118,7 +118,7 @@ - (MSALAccount *)accountWithParameters:(MSIDAutomationTestRequest *)parameters if (accountIdentifier) { - return [application accountForHomeAccountId:accountIdentifier error:error]; + return [application accountForIdentifier:accountIdentifier error:error]; } else if (parameters.legacyAccountIdentifier) { @@ -146,11 +146,11 @@ - (MSIDAutomationTestResult *)testResultWithMSALResult:(MSALResult *)msalResult NSInteger expiresOn = [msalResult.expiresOn timeIntervalSince1970]; MSIDAutomationUserInformation *userInfo = [MSIDAutomationUserInformation new]; - userInfo.objectId = msalResult.account.localAccountId.objectId; - userInfo.tenantId = msalResult.tenantId; + userInfo.objectId = msalResult.tenantProfile.claims[@"oid"]; + userInfo.tenantId = msalResult.tenantProfile.tenantId; userInfo.username = msalResult.account.username; userInfo.homeAccountId = msalResult.account.homeAccountId.identifier; - userInfo.localAccountId = msalResult.account.localAccountId.identifier; + userInfo.localAccountId = msalResult.tenantProfile.identifier; userInfo.homeObjectId = msalResult.account.homeAccountId.objectId; userInfo.homeTenantId = msalResult.account.homeAccountId.tenantId; userInfo.environment = msalResult.account.environment; diff --git a/MSAL/test/automation/ios/actions/MSALAutomationReadAccountsAction.m b/MSAL/test/automation/ios/actions/MSALAutomationReadAccountsAction.m index 227c2241c9..2386389120 100644 --- a/MSAL/test/automation/ios/actions/MSALAutomationReadAccountsAction.m +++ b/MSAL/test/automation/ios/actions/MSALAutomationReadAccountsAction.m @@ -34,6 +34,7 @@ #import "MSIDAutomationActionManager.h" #import "MSIDAutomationAccountsResult.h" #import "MSALAccount+Internal.h" +#import "MSALTenantProfile.h" @implementation MSALAutomationReadAccountsAction @@ -81,14 +82,14 @@ - (void)performActionWithParameters:(MSIDAutomationTestRequest *)testRequest for (MSALAccount *account in accounts) { MSIDAutomationUserInformation *userInfo = [MSIDAutomationUserInformation new]; - userInfo.objectId = account.localAccountId.objectId; - userInfo.tenantId = account.localAccountId.tenantId; userInfo.username = account.username; userInfo.homeAccountId = account.homeAccountId.identifier; - userInfo.localAccountId = account.localAccountId.identifier; + userInfo.localAccountId = account.tenantProfiles[0].identifier; userInfo.homeObjectId = account.homeAccountId.objectId; userInfo.homeTenantId = account.homeAccountId.tenantId; userInfo.environment = account.environment; + userInfo.objectId = account.tenantProfiles[0].claims[@"oid"]; + userInfo.tenantId = account.tenantProfiles[0].tenantId; [items addObject:userInfo]; } diff --git a/MSAL/test/automation/ios/util/MSALResult+Automation.m b/MSAL/test/automation/ios/util/MSALResult+Automation.m index 168e08d8b9..7389c274bb 100644 --- a/MSAL/test/automation/ios/util/MSALResult+Automation.m +++ b/MSAL/test/automation/ios/util/MSALResult+Automation.m @@ -27,6 +27,7 @@ #import "MSALResult+Automation.h" #import "MSALUser+Automation.h" +#import "MSALTenantProfile.h" @implementation MSALResult (Automation) @@ -34,7 +35,7 @@ - (NSDictionary *)itemAsDictionary { return @{@"access_token" : self.accessToken, @"scopes" : self.scopes, - @"tenantId" : (self.tenantId) ? self.tenantId : @"", + @"tenantId" : (self.tenantProfile.tenantId) ? self.tenantProfile.tenantId : @"", @"expires_on" : [NSString stringWithFormat:@"%f", self.expiresOn.timeIntervalSince1970], @"id_token" : self.idToken ? self.idToken : @"", @"user" : self.account ? [self.account itemAsDictionary] : @"", diff --git a/MSAL/test/automation/ios/util/MSALUser+Automation.m b/MSAL/test/automation/ios/util/MSALUser+Automation.m index be65976380..4bfa3c59d5 100644 --- a/MSAL/test/automation/ios/util/MSALUser+Automation.m +++ b/MSAL/test/automation/ios/util/MSALUser+Automation.m @@ -29,6 +29,7 @@ #import "MSIDClientInfo.h" #import "MSALAccount+Internal.h" #import "MSALAccountId.h" +#import "MSALTenantProfile.h" @implementation MSALAccount (Automation) @@ -36,9 +37,8 @@ - (NSDictionary *)itemAsDictionary { NSMutableDictionary *resultDict = [NSMutableDictionary dictionary]; [resultDict setValue:self.username forKey:@"username"]; - [resultDict setValue:self.name forKey:@"name"]; [resultDict setValue:self.homeAccountId.identifier forKey:@"home_account_id"]; - [resultDict setValue:self.localAccountId.identifier forKey:@"local_account_id"]; + [resultDict setValue:self.tenantProfiles[0].identifier forKey:@"local_account_id"]; [resultDict setValue:self.homeAccountId.objectId forKey:@"homeAccountId.objectId"]; [resultDict setValue:self.homeAccountId.tenantId forKey:@"homeAccountId.tenantId"]; [resultDict setValue:self.environment forKey:@"environment"]; diff --git a/MSAL/test/automation/tests/MSALADFSBaseUITest.m b/MSAL/test/automation/tests/MSALADFSBaseUITest.m index 9e82d10597..aa8d9ef49d 100644 --- a/MSAL/test/automation/tests/MSALADFSBaseUITest.m +++ b/MSAL/test/automation/tests/MSALADFSBaseUITest.m @@ -47,6 +47,11 @@ - (NSString *)runSharedADFSInteractiveLoginWithRequest:(MSIDAutomationTestReques [self enterADFSPassword]; [self acceptMSSTSConsentIfNecessary:@"Accept" embeddedWebView:request.usesEmbeddedWebView]; + + if (!request.usesEmbeddedWebView) + { + [self acceptSpeedBump]; + } NSString *homeAccountId = [self runSharedResultAssertionWithTestRequest:request]; diff --git a/MSAL/test/automation/tests/MSALBaseAADUITest.m b/MSAL/test/automation/tests/MSALBaseAADUITest.m index 66f2d6efe6..8bbfcf8d42 100644 --- a/MSAL/test/automation/tests/MSALBaseAADUITest.m +++ b/MSAL/test/automation/tests/MSALBaseAADUITest.m @@ -49,6 +49,11 @@ - (NSString *)runSharedAADLoginWithTestRequest:(MSIDAutomationTestRequest *)requ [self aadEnterPassword]; [self acceptMSSTSConsentIfNecessary:self.consentTitle ? self.consentTitle : @"Accept" embeddedWebView:request.usesEmbeddedWebView]; + + if (!request.usesEmbeddedWebView) + { + [self acceptSpeedBump]; + } NSString *homeAccountId = [self runSharedResultAssertionWithTestRequest:request]; diff --git a/MSAL/test/automation/tests/MSALBaseUITest.h b/MSAL/test/automation/tests/MSALBaseUITest.h index 55777d1a99..ab652a227c 100644 --- a/MSAL/test/automation/tests/MSALBaseUITest.h +++ b/MSAL/test/automation/tests/MSALBaseUITest.h @@ -69,6 +69,7 @@ - (void)adfsEnterPassword:(NSString *)password app:(XCUIApplication *)app; - (void)acceptMSSTSConsentIfNecessary:(NSString *)acceptButtonTitle embeddedWebView:(BOOL)embeddedWebView; +- (void)acceptSpeedBump; - (void)closeAuthUIUsingWebViewType:(MSIDWebviewType)webViewType passedInWebView:(BOOL)usesPassedInWebView; - (void)openURL:(NSDictionary *)config; diff --git a/MSAL/test/automation/tests/MSALBaseUITest.m b/MSAL/test/automation/tests/MSALBaseUITest.m index beb4f5791e..67d983e2d9 100644 --- a/MSAL/test/automation/tests/MSALBaseUITest.m +++ b/MSAL/test/automation/tests/MSALBaseUITest.m @@ -259,16 +259,31 @@ - (void)aadEnterPassword:(NSString *)password app:(XCUIApplication *)app - (void)acceptMSSTSConsentIfNecessary:(NSString *)acceptButtonTitle embeddedWebView:(BOOL)embeddedWebView { - XCUIElement *consentAcceptButton = self.testApp.buttons[acceptButtonTitle]; + [self acceptConsentIfNecessary:self.testApp.buttons[acceptButtonTitle] + consentButton:acceptButtonTitle + embeddedWebView:embeddedWebView]; +} - int i = 0; +- (void)acceptSpeedBump +{ + [self acceptConsentIfNecessary:self.testApp.staticTexts[@"Only continue if you downloaded the app from a store or website that you trust."] + consentButton:@"Continue" + embeddedWebView:NO]; +} +- (void)acceptConsentIfNecessary:(XCUIElement *)elementToCheck + consentButton:(NSString *)consentButton + embeddedWebView:(BOOL)embeddedWebView +{ + int i = 0; + while (i < 20) { - + // If consent button found, tap it and return - if (consentAcceptButton.exists) + if (elementToCheck.exists) { - [consentAcceptButton msidTap]; + XCUIElement *button = self.testApp.buttons[consentButton]; + [button msidTap]; return; } // If consent button is not there, but system webview is still shown, wait for 1 more second diff --git a/MSAL/test/automation/tests/interactive/MSALAADBasicInteractiveTests.m b/MSAL/test/automation/tests/interactive/MSALAADBasicInteractiveTests.m index 4f0734f4c7..7e7509a1fd 100644 --- a/MSAL/test/automation/tests/interactive/MSALAADBasicInteractiveTests.m +++ b/MSAL/test/automation/tests/interactive/MSALAADBasicInteractiveTests.m @@ -98,8 +98,10 @@ - (void)testInteractiveAADLogin_withConvergedApp_andMicrosoftGraphScopes_andComm // 5. Run silent with invalid scopes request.requestScopes = [self.class.confProvider scopesForEnvironment:self.testEnvironment type:@"unsupported"]; NSDictionary *config = [self configWithTestRequest:request]; - [self acquireTokenSilent:config]; - [self assertInternalErrorCode:MSALInternalErrorInvalidScope]; + [self acquireToken:config]; + [self acceptAuthSessionDialogIfNecessary:request]; + [self aadEnterPassword]; + [self assertInternalErrorCode:MSALInternalErrorInvalidClient]; [self closeResultView]; // 6. Run silent with not consented scopes @@ -316,6 +318,8 @@ - (void)testInteractiveAADLogin_withNonConvergedApp_andMicrosoftGraphScopes_andT [self acceptAuthSessionDialog]; [self selectAccountWithTitle:self.primaryAccount.account]; + + [self acceptSpeedBump]; [self assertAccessTokenNotNil]; [self closeResultView]; diff --git a/MSAL/test/automation/tests/interactive/MSALAADMultiUserTests.m b/MSAL/test/automation/tests/interactive/MSALAADMultiUserTests.m index 0922648402..b396aeeadf 100644 --- a/MSAL/test/automation/tests/interactive/MSALAADMultiUserTests.m +++ b/MSAL/test/automation/tests/interactive/MSALAADMultiUserTests.m @@ -135,10 +135,6 @@ - (void)testInteractiveAADLogin_withNonConvergedApp_whenWrongAccountReturned NSDictionary *config = [self configWithTestRequest:request]; [self acquireToken:config]; - - XCUIElement *signIn = self.testApp.staticTexts[@"Sign in with another account"]; - [self waitForElement:signIn]; - [signIn msidTap]; [self selectAccountWithTitle:@"Use another account"]; diff --git a/MSAL/test/automation/tests/interactive/MSALB2CInteractiveTests.m b/MSAL/test/automation/tests/interactive/MSALB2CInteractiveTests.m index 8e9f954aaf..15abb9aa9c 100644 --- a/MSAL/test/automation/tests/interactive/MSALB2CInteractiveTests.m +++ b/MSAL/test/automation/tests/interactive/MSALB2CInteractiveTests.m @@ -105,6 +105,7 @@ - (void)testInteractiveB2CLogin_withEmbeddedWebView_withoutLoginHint_withSigninP request.testAccount = [self.primaryAccount copy]; request.webViewType = MSALWebviewTypeWKWebView; request.requestIDP = @"Microsoft"; + request.promptBehavior = @"force"; request.configurationAuthority = [self.class.confProvider b2cAuthorityForIdentifier:self.testEnvironment tenantName:self.primaryAccount.tenantName policy:self.testConfiguration.policies[@"signin"]]; request.expectedResultAuthority = [self.class.confProvider b2cAuthorityForIdentifier:self.testEnvironment tenantName:self.primaryAccount.homeTenantId policy:self.testConfiguration.policies[@"signin"]]; request.cacheAuthority = [self.class.confProvider defaultAuthorityForIdentifier:self.testEnvironment tenantId:self.primaryAccount.homeTenantId]; @@ -139,6 +140,7 @@ - (void)testInteractiveB2CLogin_withEmbeddedWebView_withoutLoginHint_withSigninP request.testAccount = [self.primaryAccount copy]; request.webViewType = MSALWebviewTypeWKWebView; request.requestIDP = @"Microsoft"; + request.promptBehavior = @"force"; request.configurationAuthority = [self.class.confProvider b2cAuthorityForIdentifier:self.testEnvironment tenantName:self.primaryAccount.targetTenantId policy:self.testConfiguration.policies[@"signin"]]; request.expectedResultAuthority = [self.class.confProvider b2cAuthorityForIdentifier:self.testEnvironment tenantName:self.primaryAccount.homeTenantId policy:self.testConfiguration.policies[@"signin"]]; request.cacheAuthority = [self.class.confProvider defaultAuthorityForIdentifier:self.testEnvironment tenantId:self.primaryAccount.homeTenantId]; @@ -153,7 +155,6 @@ - (void)testInteractiveB2CLogin_withEmbeddedWebView_withoutLoginHint_withSigninP // 3. Run UI appeared step [self runSharedAuthUIAppearsStepWithTestRequest:request]; request.homeAccountIdentifier = homeAccountId; - // 4. Run silent login request.testAccount = nil; [self runSharedSilentAADLoginWithTestRequest:request]; @@ -225,6 +226,7 @@ - (void)testInteractiveB2CLogin_withPassedInWebView_withoutLoginHint_withSigninA profileRequest.extraScopes = profileRequest.requestScopes; profileRequest.testAccount = self.primaryAccount; profileRequest.usePassedWebView = YES; + profileRequest.loginHint = self.primaryAccount.username; profileRequest.requestIDP = @"Microsoft"; profileRequest.configurationAuthority = [self.class.confProvider b2cAuthorityForIdentifier:self.testEnvironment tenantName:self.primaryAccount.targetTenantId policy:self.testConfiguration.policies[@"profile"]]; profileRequest.expectedResultAuthority = [self.class.confProvider b2cAuthorityForIdentifier:self.testEnvironment tenantName:self.primaryAccount.homeTenantId policy:self.testConfiguration.policies[@"profile"]]; diff --git a/MSAL/test/automation/tests/interactive/MSALBlackforestUITests.m b/MSAL/test/automation/tests/interactive/MSALBlackforestUITests.m index cbe5c3a3bb..da005a9dda 100644 --- a/MSAL/test/automation/tests/interactive/MSALBlackforestUITests.m +++ b/MSAL/test/automation/tests/interactive/MSALBlackforestUITests.m @@ -69,11 +69,14 @@ - (void)testInteractiveAADLogin_withConvergedApp_withWWAuthority_withNoLoginHint [self runSharedAuthUIAppearsStepWithTestRequest:request]; // 3. Run silent with wrong authority + // In 0.5.0+ it should succeed + // TODO: verify expected behavior for this in 0.6.0 MSAL release request.homeAccountIdentifier = homeAccountID; request.acquireTokenAuthority = request.configurationAuthority; NSDictionary *config = [self configWithTestRequest:request]; [self acquireTokenSilent:config]; - [self assertErrorCode:MSALErrorInteractionRequired]; + [self assertAccessTokenNotNil]; + [self runSharedResultAssertionWithTestRequest:request]; [self closeResultView]; // 4. Run silent with correct authority @@ -105,10 +108,13 @@ - (void)testInteractiveAADLogin_withNonConvergedApp_withWWAuthority_withNoLoginH [self runSharedAuthUIAppearsStepWithTestRequest:request]; // 3. Run silent with wrong authority + // In 0.5.0+ it should succeed + // TODO: verify expected behavior for this in 0.6.0 MSAL release request.homeAccountIdentifier = homeAccountID; NSDictionary *config = [self configWithTestRequest:request]; [self acquireTokenSilent:config]; - [self assertErrorCode:MSALErrorInteractionRequired]; + [self assertAccessTokenNotNil]; + [self runSharedResultAssertionWithTestRequest:request]; [self closeResultView]; // 4. Run silent with correct authority diff --git a/MSAL/test/automation/tests/interactive/MSALGuestUserTests.m b/MSAL/test/automation/tests/interactive/MSALGuestUserTests.m index 38d3fa2905..e81b1f26e2 100644 --- a/MSAL/test/automation/tests/interactive/MSALGuestUserTests.m +++ b/MSAL/test/automation/tests/interactive/MSALGuestUserTests.m @@ -171,6 +171,11 @@ - (NSString *)runSharedGuestInteractiveLoginWithRequest:(MSIDAutomationTestReque [self enterGuestUsername]; [self enterGuestPassword]; [self acceptMSSTSConsentIfNecessary:@"Accept" embeddedWebView:request.usesEmbeddedWebView]; + + if (!request.usesEmbeddedWebView) + { + [self acceptSpeedBump]; + } NSString *homeAccountId = [self runSharedResultAssertionWithTestRequest:request]; diff --git a/MSAL/test/automation/tests/interactive/MSALPingUITests.m b/MSAL/test/automation/tests/interactive/MSALPingUITests.m index 0f0240c47c..ea3ca901f2 100644 --- a/MSAL/test/automation/tests/interactive/MSALPingUITests.m +++ b/MSAL/test/automation/tests/interactive/MSALPingUITests.m @@ -69,6 +69,11 @@ - (NSString *)runSharedPingInteractiveLoginWithRequest:(MSIDAutomationTestReques [self acceptMSSTSConsentIfNecessary:@"Accept" embeddedWebView:request.usesEmbeddedWebView]; + + if (!request.usesEmbeddedWebView) + { + [self acceptSpeedBump]; + } [self assertAccessTokenNotNil]; [self assertScopesReturned:[request.expectedResultScopes msidScopeSet].array]; diff --git a/MSAL/test/automation/tests/interactive/MSALShibUITests.m b/MSAL/test/automation/tests/interactive/MSALShibUITests.m index be43605692..f7482864b6 100644 --- a/MSAL/test/automation/tests/interactive/MSALShibUITests.m +++ b/MSAL/test/automation/tests/interactive/MSALShibUITests.m @@ -69,6 +69,11 @@ - (NSString *)runSharedShibbolethInteractiveLoginWithRequest:(MSIDAutomationTest [self acceptMSSTSConsentIfNecessary:@"Accept" embeddedWebView:request.usesEmbeddedWebView]; + + if (!request.usesEmbeddedWebView) + { + [self acceptSpeedBump]; + } NSString *homeAccountId = [self runSharedResultAssertionWithTestRequest:request]; [self closeResultView]; diff --git a/MSAL/test/unit/MSALAADAuthorityTests.m b/MSAL/test/unit/MSALAADAuthorityTests.m new file mode 100644 index 0000000000..0e1beb1d86 --- /dev/null +++ b/MSAL/test/unit/MSALAADAuthorityTests.m @@ -0,0 +1,95 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALAADAuthority.h" + +@interface MSALAADAuthorityTests : XCTestCase + +@end + +@implementation MSALAADAuthorityTests + +- (void)testInitWithCloudInstanceAudienceAndTenant_whenCloudInstancePublic_audienceCommon_andNilTenant_shouldReturnAuthority +{ + NSError *error = nil; + MSALAADAuthority *authority = [[MSALAADAuthority alloc] initWithCloudInstance:MSALAzurePublicCloudInstance + audienceType:MSALAzureADAndPersonalMicrosoftAccountAudience + rawTenant:nil + error:&error]; + + XCTAssertNil(error); + XCTAssertNotNil(authority); + XCTAssertEqualObjects(authority.url.absoluteString, @"https://login.microsoftonline.com/common"); +} + +- (void)testInitWithCloudInstanceAudienceAndTenant_whenCloudInstancePublic_audienceCommon_andNonNilTenant_shouldReturnError +{ + NSError *error = nil; + MSALAADAuthority *authority = [[MSALAADAuthority alloc] initWithCloudInstance:MSALAzurePublicCloudInstance + audienceType:MSALAzureADAndPersonalMicrosoftAccountAudience + rawTenant:@"contoso.com" + error:&error]; + + XCTAssertNotNil(error); + XCTAssertNil(authority); + XCTAssertEqualObjects(error.domain, MSALErrorDomain); + XCTAssertEqual(error.code, MSALErrorInternal); + XCTAssertEqual([error.userInfo[MSALInternalErrorCodeKey] integerValue], MSALInternalErrorInvalidParameter); + XCTAssertEqualObjects(error.userInfo[MSALErrorDescriptionKey], @"Invalid MSALAudienceType provided. You can only provide rawTenant when using MSALAzureADMyOrgOnlyAudience."); +} + +- (void)testInitWithCloudInstanceAudienceAndTenant_whenCloudInstancePublic_audienceMyOrg_andNilTenant_shouldReturnError +{ + NSError *error = nil; + MSALAADAuthority *authority = [[MSALAADAuthority alloc] initWithCloudInstance:MSALAzureGermanyCloudInstance + audienceType:MSALAzureADMyOrgOnlyAudience + rawTenant:nil + error:&error]; + + XCTAssertNotNil(error); + XCTAssertNil(authority); + XCTAssertEqualObjects(error.domain, MSALErrorDomain); + XCTAssertEqual(error.code, MSALErrorInternal); + XCTAssertEqual([error.userInfo[MSALInternalErrorCodeKey] integerValue], MSALInternalErrorInvalidParameter); + XCTAssertEqualObjects(error.userInfo[MSALErrorDescriptionKey], @"Invalid MSALAudienceType provided. You must provide rawTenant when using MSALAzureADMyOrgOnlyAudience."); +} + +- (void)testInitWithCloudInstanceAudienceAndTenant_whenCloudInstancePublic_audienceMyOrg_andNonNilTenant_shouldReturnAuthority +{ + NSError *error = nil; + MSALAADAuthority *authority = [[MSALAADAuthority alloc] initWithCloudInstance:MSALAzureGermanyCloudInstance + audienceType:MSALAzureADMyOrgOnlyAudience + rawTenant:@"contoso.de" + error:&error]; + + XCTAssertNil(error); + XCTAssertNotNil(authority); + XCTAssertEqualObjects(authority.url.absoluteString, @"https://login.microsoftonline.de/contoso.de"); +} + +@end diff --git a/MSAL/test/unit/MSALAccountIdTests.m b/MSAL/test/unit/MSALAccountIdTests.m index ad2ffb29ce..0477072825 100644 --- a/MSAL/test/unit/MSALAccountIdTests.m +++ b/MSAL/test/unit/MSALAccountIdTests.m @@ -75,7 +75,7 @@ - (void)testIsEqual_whenNotEqualWithNilParam_shouldReturnNO objectId:@"objectId" tenantId:@"tenantId"]; - MSALAccountId *accountId2 = [[MSALAccountId alloc] initWithAccountIdentifier:@"identifier" + MSALAccountId *accountId2 = [[MSALAccountId alloc] initWithAccountIdentifier:@"identifier2" objectId:@"objectId" tenantId:nil]; diff --git a/MSAL/test/unit/MSALAccountTests.m b/MSAL/test/unit/MSALAccountTests.m new file mode 100644 index 0000000000..452490e5bb --- /dev/null +++ b/MSAL/test/unit/MSALAccountTests.m @@ -0,0 +1,327 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALTestCase.h" +#import "MSIDClientInfo.h" +#import "MSIDAADV2IdTokenClaims.h" +#import "MSALAccount+Internal.h" +#import "MSIDAccount.h" +#import "MSALAccountId.h" +#import "MSIDAADAuthority.h" +#import "MSIDAccountIdentifier.h" +#import "MSIDAuthority+Internal.h" +#import "MSALTenantProfile.h" +#import "MSALTenantProfile+Internal.h" +#import "MSALAccount+Internal.h" +#import "MSALAuthority.h" +#import "MSALAccountId+Internal.h" +#import "MSALAccount+MultiTenantAccount.h" + +@interface MSALUserTests : MSALTestCase + +@end + +@implementation MSALUserTests + +- (void)setUp { + [super setUp]; + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +- (void)testInitWithMSIDAccount_whenValidAccountAndCreateTenantProfileYes_shouldInitAndCreateTenantProfile +{ + MSIDAccount *msidAccount = [MSIDAccount new]; + msidAccount.accountIdentifier = [[MSIDAccountIdentifier alloc] initWithDisplayableId:@"user@contoso.com" homeAccountId:@"uid.tid"]; + msidAccount.username = @"user@contoso.com"; + msidAccount.name = @"User"; + msidAccount.localAccountId = @"localoid"; + __auto_type authorityUrl = [NSURL URLWithString:@"https://login.microsoftonline.com/tid"]; + __auto_type authority = [[MSIDAADAuthority alloc] initWithURL:authorityUrl context:nil error:nil]; + msidAccount.environment = authority.environment; + msidAccount.realm = authority.realm; + NSDictionary *clientInfoClaims = @{ @"uid" : @"uid", + @"utid" : @"tid" + }; + + + MSIDClientInfo *clientInfo = [[MSIDClientInfo alloc] initWithJSONDictionary:clientInfoClaims error:nil]; + msidAccount.clientInfo = clientInfo; + + NSDictionary *idTokenDictionary = @{ @"aud" : @"b6c69a37", + @"oid" : @"ff9feb5a" + }; + + MSIDIdTokenClaims *idTokenClaims = [[MSIDIdTokenClaims alloc] initWithJSONDictionary:idTokenDictionary error:nil]; + XCTAssertNotNil(idTokenClaims); + msidAccount.idTokenClaims = idTokenClaims; + MSALAccount *account = [[MSALAccount alloc] initWithMSIDAccount:msidAccount createTenantProfile:YES]; + + XCTAssertNotNil(account); + XCTAssertEqualObjects(account.homeAccountId.objectId, @"uid"); + XCTAssertEqualObjects(account.homeAccountId.tenantId, @"tid"); + XCTAssertEqualObjects(account.username, @"user@contoso.com"); + XCTAssertEqualObjects(account.identifier, @"uid.tid"); + XCTAssertNil(account.accountClaims); + XCTAssertEqual(account.tenantProfiles.count, 1); + XCTAssertEqualObjects(account.tenantProfiles[0].identifier, @"localoid"); + XCTAssertEqualObjects(account.tenantProfiles[0].tenantId, @"tid"); + XCTAssertEqual(account.tenantProfiles[0].isHomeTenantProfile, YES); + XCTAssertEqualObjects(account.tenantProfiles[0].environment, authority.environment); + XCTAssertEqualObjects(account.tenantProfiles[0].tenantId, authority.realm); + XCTAssertEqualObjects(account.tenantProfiles[0].claims, idTokenDictionary); +} + +- (void)testInitWithMSIDAccount_whenValidAccountAndCreateTenantProfileNo_shouldInitAndNotCreateTenantProfile +{ + MSIDAccount *msidAccount = [MSIDAccount new]; + msidAccount.accountIdentifier = [[MSIDAccountIdentifier alloc] initWithDisplayableId:@"user@contoso.com" homeAccountId:@"uid.tid"]; + msidAccount.username = @"user@contoso.com"; + msidAccount.name = @"User"; + msidAccount.localAccountId = @"localoid"; + __auto_type authorityUrl = [NSURL URLWithString:@"https://login.microsoftonline.com/tid"]; + __auto_type authority = [[MSIDAADAuthority alloc] initWithURL:authorityUrl context:nil error:nil]; + msidAccount.environment = authority.environment; + msidAccount.realm = authority.realm; + NSDictionary *clientInfoClaims = @{ @"uid" : @"uid", + @"utid" : @"tid" + }; + + + MSIDClientInfo *clientInfo = [[MSIDClientInfo alloc] initWithJSONDictionary:clientInfoClaims error:nil]; + msidAccount.clientInfo = clientInfo; + + NSDictionary *idTokenDictionary = @{ @"aud" : @"b6c69a37", + @"oid" : @"ff9feb5a" + }; + + MSIDIdTokenClaims *idTokenClaims = [[MSIDIdTokenClaims alloc] initWithJSONDictionary:idTokenDictionary error:nil]; + XCTAssertNotNil(idTokenClaims); + msidAccount.idTokenClaims = idTokenClaims; + MSALAccount *account = [[MSALAccount alloc] initWithMSIDAccount:msidAccount createTenantProfile:NO]; + + XCTAssertNotNil(account); + XCTAssertEqualObjects(account.homeAccountId.objectId, @"uid"); + XCTAssertEqualObjects(account.homeAccountId.tenantId, @"tid"); + XCTAssertEqualObjects(account.username, @"user@contoso.com"); + XCTAssertEqualObjects(account.identifier, @"uid.tid"); + XCTAssertNil(account.accountClaims); + XCTAssertNil(account.tenantProfiles); +} + +- (void)testAddTenantProfiles_whenAddValidTenantProfiles_shouldAddIt +{ + // Create MSAL account 1 + MSIDAccount *msidAccount = [MSIDAccount new]; + msidAccount.accountIdentifier = [[MSIDAccountIdentifier alloc] initWithDisplayableId:@"user@contoso.com" homeAccountId:@"uid.tid"]; + msidAccount.username = @"user@contoso.com"; + msidAccount.accountType = MSIDAccountTypeMSSTS; + msidAccount.name = @"User"; + msidAccount.localAccountId = @"guest_oid"; + __auto_type authorityUrl = [NSURL URLWithString:@"https://login.microsoftonline.com/guest_tid"]; + __auto_type authority = [[MSIDAADAuthority alloc] initWithURL:authorityUrl context:nil error:nil]; + msidAccount.environment = authority.environment; + msidAccount.realm = authority.realm; + NSDictionary *clientInfoClaims = @{ @"uid" : @"uid", + @"utid" : @"tid" + }; + + + MSIDClientInfo *clientInfo = [[MSIDClientInfo alloc] initWithJSONDictionary:clientInfoClaims error:nil]; + msidAccount.clientInfo = clientInfo; + + NSDictionary *idTokenDictionary = @{ @"aud" : @"b6c69a37", + @"oid" : @"ff9feb5a" + }; + + MSIDIdTokenClaims *idTokenClaims = [[MSIDIdTokenClaims alloc] initWithJSONDictionary:idTokenDictionary error:nil]; + XCTAssertNotNil(idTokenClaims); + msidAccount.idTokenClaims = idTokenClaims; + MSALAccount *account = [[MSALAccount alloc] initWithMSIDAccount:msidAccount createTenantProfile:YES]; + + // Create MSAL account 2 + MSIDAccount *msidAccount2 = [msidAccount copy]; + msidAccount2.localAccountId = @"oid"; + __auto_type homeAuthorityUrl = [NSURL URLWithString:@"https://login.microsoftonline.com/tid"]; + __auto_type homeAuthority = [[MSIDAADAuthority alloc] initWithURL:homeAuthorityUrl context:nil error:nil]; + msidAccount2.environment = homeAuthority.environment; + msidAccount2.realm = homeAuthority.realm; + + MSALAccount *account2 = [[MSALAccount alloc] initWithMSIDAccount:msidAccount2 createTenantProfile:YES]; + XCTAssertNotNil(account2); + + // Add tenant profiles + [account addTenantProfiles:account2.tenantProfiles]; + + XCTAssertEqual(account.tenantProfiles.count, 2); + XCTAssertEqualObjects(account.tenantProfiles[0].identifier, @"guest_oid"); + XCTAssertEqualObjects(account.tenantProfiles[0].tenantId, @"guest_tid"); + XCTAssertEqual(account.tenantProfiles[0].isHomeTenantProfile, NO); + XCTAssertEqualObjects(account.tenantProfiles[1].identifier, @"oid"); + XCTAssertEqualObjects(account.tenantProfiles[1].tenantId, @"tid"); + XCTAssertEqual(account.tenantProfiles[1].isHomeTenantProfile, YES); +} + +- (void)testAddTenantProfiles_whenAddNilTenantProfiles_shouldNotAddToExistingAccount +{ + MSALAuthority *authority = [MSALAuthority authorityWithURL:[NSURL URLWithString:@"https://login.microsoftonline.com/tid"] + error:nil]; + XCTAssertNotNil(authority); + MSALTenantProfile *tenantProfile = [[MSALTenantProfile alloc] initWithIdentifier:@"1" + tenantId:@"2" + environment:@"login.microsoftonline.com" + isHomeTenantProfile:YES + claims:@{@"key" : @"value"}]; + + MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.2" objectId:@"1" tenantId:@"2"]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"displayableID" + homeAccountId:accountId + environment:@"login.microsoftonline.com" + tenantProfiles:@[tenantProfile]]; + XCTAssertNotNil(account); + + [account addTenantProfiles:nil]; + + XCTAssertEqual(account.tenantProfiles.count, 1); + XCTAssertEqualObjects(account.tenantProfiles[0].identifier, @"1"); + XCTAssertEqualObjects(account.tenantProfiles[0].tenantId, @"2"); +} + +- (void)testAddTenantProfiles_whenAddEmptyTenantProfiles_shouldNotAddToExistingAccount +{ + MSALAuthority *authority = [MSALAuthority authorityWithURL:[NSURL URLWithString:@"https://login.microsoftonline.com/tid"] + error:nil]; + XCTAssertNotNil(authority); + + MSALTenantProfile *tenantProfile = [[MSALTenantProfile alloc] initWithIdentifier:@"1" + tenantId:@"tid" + environment:@"login.microsoftonline.com" + isHomeTenantProfile:YES + claims:@{@"key" : @"value"}]; + + MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.2" objectId:@"1" tenantId:@"2"]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"displayableID" + homeAccountId:accountId + environment:@"login.microsoftonline.com" + tenantProfiles:@[tenantProfile]]; + XCTAssertNotNil(account); + + [account addTenantProfiles:[NSArray new]]; + + XCTAssertEqual(account.tenantProfiles.count, 1); + XCTAssertEqualObjects(account.tenantProfiles[0].identifier, @"1"); + XCTAssertEqualObjects(account.tenantProfiles[0].tenantId, @"tid"); +} + +- (void)testCopy_whenValidAccount_shouldDeepCopy +{ + MSALAuthority *authority = [MSALAuthority authorityWithURL:[NSURL URLWithString:@"https://login.microsoftonline.com/tid"] + error:nil]; + XCTAssertNotNil(authority); + + MSALTenantProfile *tenantProfile = [[MSALTenantProfile alloc] initWithIdentifier:@"oid" + tenantId:@"tid" + environment:@"login.microsoftonline.com" + isHomeTenantProfile:YES + claims:@{@"key" : @"value"}]; + + authority = [MSALAuthority authorityWithURL:[NSURL URLWithString:@"https://login.microsoftonline.com/tid2"] + error:nil]; + XCTAssertNotNil(authority); + + MSALTenantProfile *tenantProfile2 = [[MSALTenantProfile alloc] initWithIdentifier:@"oid2" + tenantId:@"tid2" + environment:@"login.microsoftonline.com" + isHomeTenantProfile:YES + claims:@{@"key" : @"value"}]; + + MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.2" objectId:@"1" tenantId:@"2"]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"displayableID" + homeAccountId:accountId + environment:@"login.microsoftonline.com" + tenantProfiles:@[tenantProfile, tenantProfile2]]; + XCTAssertNotNil(account); + XCTAssertEqual(account.tenantProfiles.count, 2); + + MSALAccount *account2 = [account copy]; + + XCTAssertNotNil(account2); + + // The two objects should have different pointers + XCTAssertNotEqual(account, account2); + XCTAssertEqualObjects(account.homeAccountId.objectId, account2.homeAccountId.objectId); + XCTAssertEqualObjects(account.homeAccountId.tenantId, account2.homeAccountId.tenantId); + XCTAssertEqualObjects(account.environment, account2.environment); + XCTAssertEqualObjects(account.username, account2.username); + XCTAssertEqualObjects(account.identifier, account2.identifier); + XCTAssertEqualObjects(account.accountClaims, account2.accountClaims); + + // tenantProfiles should be deep copied and have different pointers + XCTAssertNotEqual(account.tenantProfiles, account2.tenantProfiles); + XCTAssertEqual(account.tenantProfiles.count, account2.tenantProfiles.count); + XCTAssertNotEqual(account.tenantProfiles[0], account2.tenantProfiles[0]); + XCTAssertNotEqual(account.tenantProfiles[1], account2.tenantProfiles[1]); + + XCTAssertEqualObjects(account.tenantProfiles[0].tenantId, account2.tenantProfiles[0].tenantId); + XCTAssertEqualObjects(account.tenantProfiles[0].identifier, account2.tenantProfiles[0].identifier); + XCTAssertEqualObjects(account.tenantProfiles[0].environment, account2.tenantProfiles[0].environment); + XCTAssertEqualObjects(account.tenantProfiles[0].tenantId, account2.tenantProfiles[0].tenantId); + XCTAssertEqual(account.tenantProfiles[0].isHomeTenantProfile, account2.tenantProfiles[0].isHomeTenantProfile); + + XCTAssertEqualObjects(account.tenantProfiles[1].tenantId, account2.tenantProfiles[1].tenantId); + XCTAssertEqualObjects(account.tenantProfiles[1].identifier, account2.tenantProfiles[1].identifier); + XCTAssertEqualObjects(account.tenantProfiles[1].environment, account2.tenantProfiles[1].environment); + XCTAssertEqualObjects(account.tenantProfiles[1].tenantId, account2.tenantProfiles[1].tenantId); + XCTAssertEqual(account.tenantProfiles[1].isHomeTenantProfile, account2.tenantProfiles[1].isHomeTenantProfile); + + // claims should be deep copied + XCTAssertNotEqual(account.tenantProfiles[0].claims, account2.tenantProfiles[0].claims); + XCTAssertEqualObjects(account.tenantProfiles[0].claims, account2.tenantProfiles[0].claims); + XCTAssertNotEqual(account.tenantProfiles[1].claims, account2.tenantProfiles[1].claims); + XCTAssertEqualObjects(account.tenantProfiles[1].claims, account2.tenantProfiles[1].claims); +} + +- (void)testEquals_whenEqual_shouldReturnTrue +{ + MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.2" objectId:@"1" tenantId:@"2"]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"displayableID" + homeAccountId:accountId + environment:@"login.microsoftonline.com" + tenantProfiles:nil]; + + XCTAssertNotNil(account); + MSALAccount *account2 = [account copy]; + + XCTAssertNotNil(account2); + XCTAssertEqualObjects(account, account2); +} + +@end diff --git a/MSAL/test/unit/MSALAccountsProviderTests.m b/MSAL/test/unit/MSALAccountsProviderTests.m new file mode 100644 index 0000000000..a1e5a11daf --- /dev/null +++ b/MSAL/test/unit/MSALAccountsProviderTests.m @@ -0,0 +1,1104 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALAccountsProvider.h" +#import "MSIDDefaultTokenCacheAccessor.h" +#import "MSIDLegacyTokenCacheAccessor.h" +#import "MSIDKeychainTokenCache.h" +#import "MSALAccount.h" +#import "MSALAccount+Internal.h" +#import "MSIDAccountIdentifier.h" +#import "MSALTenantProfile.h" +#import "MSALAuthority.h" +#import "MSALAccountId.h" +#import "NSString+MSIDTestUtil.h" +#import "MSIDTestURLSession.h" +#import "MSIDTestURLResponse+Util.h" +#import "MSIDTestURLResponse+MSAL.h" +#import "MSALAADAuthority.h" +#import "MSIDAADNetworkConfiguration.h" +#import "MSIDConstants.h" +#import "MSIDTestCacheUtil.h" +#import "MSALAccount+MultiTenantAccount.h" +#import "MSALAccountEnumerationParameters.h" +#import "MSALMockExternalAccountHandler.h" +#import "MSALAADOauth2Provider.h" +#import "MSALAccountId+Internal.h" +#import "MSALTenantProfile+Internal.h" + +@interface MSALAccountsProviderTests : XCTestCase + +@end + +@implementation MSALAccountsProviderTests +{ + MSIDDefaultTokenCacheAccessor *defaultCache; + MSIDLegacyTokenCacheAccessor *legacyCache; +} + +- (void)setUp { + id dataSource = nil; + +#if TARGET_OS_IPHONE + dataSource = MSIDKeychainTokenCache.defaultKeychainCache; +#else + dataSource = MSIDMacTokenCache.defaultCache; +#endif + + legacyCache = [[MSIDLegacyTokenCacheAccessor alloc] initWithDataSource:dataSource + otherCacheAccessors:@[]]; + defaultCache = [[MSIDDefaultTokenCacheAccessor alloc] initWithDataSource:dataSource otherCacheAccessors:@[legacyCache]]; + + [defaultCache clearWithContext:nil error:nil]; + + MSIDAADNetworkConfiguration.defaultConfiguration.aadApiVersion = @"v2.0"; +} + +- (void)testAllAccounts_whenNoAccountInCache_shouldReturnEmptyList { + MSALAccountsProvider *provider = [[MSALAccountsProvider alloc] initWithTokenCache:defaultCache clientId:@"a_different_client_id"]; + + NSError *error; + NSArray *allAccounts = [provider allAccounts:&error]; + XCTAssertNil(error); + XCTAssertNotNil(allAccounts); + XCTAssertEqual(allAccounts.count, 0); +} + +- (void)testAllAccounts_whenAccountWithDifferentClientIdInCache_shouldReturnEmptyList { + MSALAccountsProvider *provider = [[MSALAccountsProvider alloc] initWithTokenCache:defaultCache clientId:@"some_client_id"]; + + [MSIDTestCacheUtil saveDefaultTokensWithAuthority:@"https://login.microsoftonline.com/tid" + clientId:@"client_id" + upn:@"user@contoso.com" + name:@"simple_user" + uid:@"uid" + utid:@"tid" + oid:@"oid" + tenantId:@"tid" + familyId:nil + cacheAccessor:defaultCache]; + + NSError *error; + NSArray *allAccounts = [provider allAccounts:&error]; + XCTAssertNil(error); + XCTAssertNotNil(allAccounts); + XCTAssertEqual(allAccounts.count, 0); +} + +- (void)testAllAccounts_whenDefaultAccountInCache_shouldReturnAccount { + MSALAccountsProvider *provider = [[MSALAccountsProvider alloc] initWithTokenCache:defaultCache clientId:@"client_id"]; + + [MSIDTestCacheUtil saveDefaultTokensWithAuthority:@"https://login.microsoftonline.com/tid" + clientId:@"client_id" + upn:@"user@contoso.com" + name:@"simple_user" + uid:@"uid" + utid:@"tid" + oid:@"oid" + tenantId:@"tid" + familyId:nil + cacheAccessor:defaultCache]; + + NSError *error; + NSArray *allAccounts = [provider allAccounts:&error]; + XCTAssertNil(error); + XCTAssertNotNil(allAccounts); + XCTAssertEqual(allAccounts.count, 1); + XCTAssertEqualObjects(allAccounts[0].username, @"user@contoso.com"); + XCTAssertEqualObjects(allAccounts[0].homeAccountId.identifier, @"uid.tid"); + XCTAssertEqualObjects(allAccounts[0].environment, @"login.microsoftonline.com"); + XCTAssertEqualObjects(allAccounts[0].lookupAccountIdentifier.homeAccountId, @"uid.tid"); + XCTAssertEqual(allAccounts[0].tenantProfiles.count, 1); + XCTAssertEqualObjects(allAccounts[0].identifier, @"uid.tid"); + XCTAssertTrue(allAccounts[0].accountClaims.count > 0); + XCTAssertEqualObjects(allAccounts[0].tenantProfiles[0].tenantId, @"tid"); + XCTAssertEqualObjects(allAccounts[0].tenantProfiles[0].environment, @"login.microsoftonline.com"); + XCTAssertEqualObjects(allAccounts[0].tenantProfiles[0].identifier, @"oid"); + XCTAssertEqualObjects(allAccounts[0].tenantProfiles[0].tenantId, @"tid"); + XCTAssertTrue(allAccounts[0].tenantProfiles[0].claims.count > 0); +} + +- (void)testAllAccounts_whenLegacyAccountInCache_shouldReturnAccount { + MSALAccountsProvider *provider = [[MSALAccountsProvider alloc] initWithTokenCache:defaultCache clientId:@"client_id"]; + + [MSIDTestCacheUtil saveLegacyTokensWithAuthority:@"https://login.microsoftonline.com/tid" + clientId:@"client_id" + upn:@"user@contoso.com" + name:@"simple_user" + uid:@"uid" + utid:@"tid" + oid:@"oid" + tenantId:@"tid" + familyId:nil + cacheAccessor:legacyCache]; + + NSError *error; + NSArray *allAccounts = [provider allAccounts:&error]; + XCTAssertNil(error); + XCTAssertNotNil(allAccounts); + XCTAssertEqual(allAccounts.count, 1); + XCTAssertEqualObjects(allAccounts[0].username, @"user@contoso.com"); + XCTAssertEqualObjects(allAccounts[0].homeAccountId.identifier, @"uid.tid"); + XCTAssertEqualObjects(allAccounts[0].environment, @"login.microsoftonline.com"); + XCTAssertEqualObjects(allAccounts[0].lookupAccountIdentifier.homeAccountId, @"uid.tid"); + XCTAssertEqual(allAccounts[0].tenantProfiles.count, 1); + XCTAssertEqualObjects(allAccounts[0].identifier, @"uid.tid"); + XCTAssertTrue(allAccounts[0].accountClaims.count > 0); + XCTAssertEqualObjects(allAccounts[0].tenantProfiles[0].tenantId, @"tid"); + XCTAssertEqualObjects(allAccounts[0].tenantProfiles[0].environment, @"login.microsoftonline.com"); + XCTAssertEqualObjects(allAccounts[0].tenantProfiles[0].identifier, @"oid"); + XCTAssertEqualObjects(allAccounts[0].tenantProfiles[0].tenantId, @"tid"); + XCTAssertTrue(allAccounts[0].tenantProfiles[0].claims.count > 0); +} + +- (void)testAllAccounts_whenDefaultAccountInCacheButDifferentClientId_shouldNotFindIt { + MSALAccountsProvider *provider = [[MSALAccountsProvider alloc] initWithTokenCache:defaultCache clientId:@"client_id"]; + + [MSIDTestCacheUtil saveDefaultTokensWithAuthority:@"https://login.microsoftonline.com/tid" + clientId:@"different_client_id" + upn:@"user@contoso.com" + name:@"simple_user" + uid:@"uid" + utid:@"tid" + oid:@"oid" + tenantId:@"tid" + familyId:nil + cacheAccessor:defaultCache]; + + NSError *error; + NSArray *allAccounts = [provider allAccounts:&error]; + XCTAssertNil(error); + XCTAssertNotNil(allAccounts); + XCTAssertEqual(allAccounts.count, 0); +} + +- (void)testAllAccounts_whenDefaultAccountInCacheWithDifferentClientIdButSameFamily_shouldFindItButNotExposeAllClaims { + MSALAccountsProvider *provider = [[MSALAccountsProvider alloc] initWithTokenCache:defaultCache clientId:@"client_id"]; + + MSIDAuthority *authority = [@"https://login.microsoftonline.com/tid" aadAuthority]; + + [MSIDTestCacheUtil saveDefaultTokensWithAuthority:authority.url.absoluteString + clientId:@"different_client_id" + upn:@"user@contoso.com" + name:@"simple_user" + uid:@"uid" + utid:@"tid" + oid:@"oid" + tenantId:@"tid" + familyId:@"1" + cacheAccessor:defaultCache]; + [defaultCache updateAppMetadataWithFamilyId:@"1" clientId:@"client_id" authority:authority context:nil error:nil]; + + NSError *error; + NSArray *allAccounts = [provider allAccounts:&error]; + XCTAssertNil(error); + XCTAssertNotNil(allAccounts); + XCTAssertEqual(allAccounts.count, 1); + XCTAssertEqualObjects(allAccounts[0].username, @"user@contoso.com"); + XCTAssertEqualObjects(allAccounts[0].homeAccountId.identifier, @"uid.tid"); + XCTAssertEqualObjects(allAccounts[0].environment, @"login.microsoftonline.com"); + XCTAssertEqualObjects(allAccounts[0].lookupAccountIdentifier.homeAccountId, @"uid.tid"); + XCTAssertEqualObjects(allAccounts[0].identifier, @"uid.tid"); + XCTAssertNil(allAccounts[0].accountClaims); + XCTAssertEqual(allAccounts[0].tenantProfiles.count, 1); + XCTAssertEqualObjects(allAccounts[0].tenantProfiles[0].tenantId, @"tid"); + XCTAssertEqualObjects(allAccounts[0].tenantProfiles[0].environment, @"login.microsoftonline.com"); + XCTAssertEqualObjects(allAccounts[0].tenantProfiles[0].identifier, @"oid"); + XCTAssertEqualObjects(allAccounts[0].tenantProfiles[0].tenantId, @"tid"); + XCTAssertNil(allAccounts[0].tenantProfiles[0].claims); +} + +- (void)testAllAccounts_whenLegacyAccountInCacheButDifferentClientId_shouldNotFindIt { + MSALAccountsProvider *provider = [[MSALAccountsProvider alloc] initWithTokenCache:defaultCache clientId:@"client_id"]; + + [MSIDTestCacheUtil saveLegacyTokensWithAuthority:@"https://login.microsoftonline.com/tid" + clientId:@"different_client_id" + upn:@"user@contoso.com" + name:@"simple_user" + uid:@"uid" + utid:@"tid" + oid:@"oid" + tenantId:@"tid" + familyId:nil + cacheAccessor:legacyCache]; + + NSError *error; + NSArray *allAccounts = [provider allAccounts:&error]; + XCTAssertNil(error); + XCTAssertNotNil(allAccounts); + XCTAssertEqual(allAccounts.count, 0); +} + +- (void)testAllAccounts_whenLegacyAccountInCacheWithDifferentClientIdButSameFamily_shouldFindItButNotExposeAllClaims { + MSALAccountsProvider *provider = [[MSALAccountsProvider alloc] initWithTokenCache:defaultCache clientId:@"client_id"]; + + MSIDAuthority *authority = [@"https://login.microsoftonline.com/tid" aadAuthority]; + + [MSIDTestCacheUtil saveLegacyTokensWithAuthority:authority.url.absoluteString + clientId:@"different_client_id" + upn:@"user@contoso.com" + name:@"simple_user" + uid:@"uid" + utid:@"tid" + oid:@"oid" + tenantId:@"tid" + familyId:@"1" + cacheAccessor:legacyCache]; + [defaultCache updateAppMetadataWithFamilyId:@"1" clientId:@"client_id" authority:authority context:nil error:nil]; + + NSError *error; + NSArray *allAccounts = [provider allAccounts:&error]; + XCTAssertNil(error); + XCTAssertNotNil(allAccounts); + XCTAssertEqual(allAccounts.count, 1); + XCTAssertEqualObjects(allAccounts[0].username, @"user@contoso.com"); + XCTAssertEqualObjects(allAccounts[0].homeAccountId.identifier, @"uid.tid"); + XCTAssertEqualObjects(allAccounts[0].environment, @"login.microsoftonline.com"); + XCTAssertEqualObjects(allAccounts[0].lookupAccountIdentifier.homeAccountId, @"uid.tid"); + XCTAssertEqual(allAccounts[0].tenantProfiles.count, 1); + XCTAssertEqualObjects(allAccounts[0].identifier, @"uid.tid"); + XCTAssertNil(allAccounts[0].accountClaims); + XCTAssertEqualObjects(allAccounts[0].tenantProfiles[0].tenantId, @"tid"); + XCTAssertEqualObjects(allAccounts[0].tenantProfiles[0].environment, @"login.microsoftonline.com"); + XCTAssertEqualObjects(allAccounts[0].tenantProfiles[0].identifier, @"oid"); + XCTAssertEqualObjects(allAccounts[0].tenantProfiles[0].tenantId, @"tid"); + XCTAssertNil(allAccounts[0].tenantProfiles[0].claims); +} + +- (void)testAllAccounts_whenMultipleDefaultAccountsInCache_shouldReturnThem { + MSALAccountsProvider *provider = [[MSALAccountsProvider alloc] initWithTokenCache:defaultCache clientId:@"client_id"]; + + // first user logged in 1 home tenant and 2 guest tenants + [MSIDTestCacheUtil saveDefaultTokensWithAuthority:@"https://login.microsoftonline.com/tid" + clientId:@"client_id" + upn:@"user@contoso.com" + name:@"contoso_user" + uid:@"uid" + utid:@"tid" + oid:@"oid" + tenantId:@"tid" + familyId:nil + cacheAccessor:defaultCache]; + + [MSIDTestCacheUtil saveDefaultTokensWithAuthority:@"https://login.microsoftonline.com/guest_tid" + clientId:@"client_id" + upn:@"user@contoso.com" + name:@"contoso_user" + uid:@"uid" + utid:@"tid" + oid:@"guest_oid" + tenantId:@"guest_tid" + familyId:nil + cacheAccessor:defaultCache]; + + [MSIDTestCacheUtil saveDefaultTokensWithAuthority:@"https://login.microsoftonline.com/guest2_tid" + clientId:@"client_id" + upn:@"user@contoso.com" + name:@"contoso_user" + uid:@"uid" + utid:@"tid" + oid:@"guest2_oid" + tenantId:@"guest2_tid" + familyId:nil + cacheAccessor:defaultCache]; + + // second user logged in 1 home tenant and 1 guest tenant + [MSIDTestCacheUtil saveDefaultTokensWithAuthority:@"https://login.microsoftonline.com/tid2" + clientId:@"client_id" + upn:@"user@fabricant.com" + name:@"fabricant_user" + uid:@"uid2" + utid:@"tid2" + oid:@"oid2" + tenantId:@"tid2" + familyId:nil + cacheAccessor:defaultCache]; + + [MSIDTestCacheUtil saveDefaultTokensWithAuthority:@"https://login.microsoftonline.com/guest_tid2" + clientId:@"client_id" + upn:@"user@fabricant.com" + name:@"fabricant_user" + uid:@"uid2" + utid:@"tid2" + oid:@"guest_oid2" + tenantId:@"guest_tid2" + familyId:nil + cacheAccessor:defaultCache]; + + NSError *error; + NSArray *allAccounts = [provider allAccounts:&error]; + XCTAssertNil(error); + XCTAssertNotNil(allAccounts); + XCTAssertEqual(allAccounts.count, 2); + + // verify first account + MSALAccount *firstAccount = [self accountWithIdentifier:@"uid.tid" fromArray:allAccounts]; + XCTAssertNotNil(firstAccount); + + XCTAssertEqualObjects(firstAccount.username, @"user@contoso.com"); + XCTAssertEqualObjects(firstAccount.homeAccountId.identifier, @"uid.tid"); + XCTAssertEqualObjects(firstAccount.environment, @"login.microsoftonline.com"); + XCTAssertEqualObjects(firstAccount.lookupAccountIdentifier.homeAccountId, @"uid.tid"); + XCTAssertEqualObjects(firstAccount.identifier, @"uid.tid"); + XCTAssertTrue(firstAccount.accountClaims.count > 0); + + // expect 3 tenant profiles + XCTAssertEqual(firstAccount.tenantProfiles.count, 3); + + NSInteger a1FirstProfileIndex = [self indexOfTenantProfileInArray:firstAccount.tenantProfiles localAccountId:@"oid"]; + + [self verifyTenantProfileWithIndex:a1FirstProfileIndex + tenantId:@"tid" + environment:@"login.microsoftonline.com" + localAccountId:@"oid" + allProfiles:firstAccount.tenantProfiles + hasClaims:YES]; + + NSInteger a1SecondProfileIndex = [self indexOfTenantProfileInArray:firstAccount.tenantProfiles localAccountId:@"guest_oid"]; + + [self verifyTenantProfileWithIndex:a1SecondProfileIndex + tenantId:@"guest_tid" + environment:@"login.microsoftonline.com" + localAccountId:@"guest_oid" + allProfiles:firstAccount.tenantProfiles + hasClaims:YES]; + + NSInteger a1ThirdProfileIndex = [self indexOfTenantProfileInArray:firstAccount.tenantProfiles localAccountId:@"guest2_oid"]; + + [self verifyTenantProfileWithIndex:a1ThirdProfileIndex + tenantId:@"guest2_tid" + environment:@"login.microsoftonline.com" + localAccountId:@"guest2_oid" + allProfiles:firstAccount.tenantProfiles + hasClaims:YES]; + + // verify second account + MSALAccount *secondAccount = [self accountWithIdentifier:@"uid2.tid2" fromArray:allAccounts]; + XCTAssertNotNil(secondAccount); + + XCTAssertEqualObjects(secondAccount.username, @"user@fabricant.com"); + XCTAssertEqualObjects(secondAccount.homeAccountId.identifier, @"uid2.tid2"); + XCTAssertEqualObjects(secondAccount.environment, @"login.microsoftonline.com"); + XCTAssertEqualObjects(secondAccount.lookupAccountIdentifier.homeAccountId, @"uid2.tid2"); + XCTAssertEqualObjects(secondAccount.identifier, @"uid2.tid2"); + XCTAssertTrue(secondAccount.accountClaims.count > 0); + + // expect 2 tenant profiles + XCTAssertEqual(secondAccount.tenantProfiles.count, 2); + + // Since tenant profiles operate using a set, there's no guarantee regarding returned order + NSInteger a2firstProfileIndex = [self indexOfTenantProfileInArray:secondAccount.tenantProfiles localAccountId:@"oid2"]; + + [self verifyTenantProfileWithIndex:a2firstProfileIndex + tenantId:@"tid2" + environment:@"login.microsoftonline.com" + localAccountId:@"oid2" + allProfiles:secondAccount.tenantProfiles + hasClaims:YES]; + + NSInteger a2secondProfileIndex = [self indexOfTenantProfileInArray:secondAccount.tenantProfiles localAccountId:@"guest_oid2"]; + [self verifyTenantProfileWithIndex:a2secondProfileIndex + tenantId:@"guest_tid2" + environment:@"login.microsoftonline.com" + localAccountId:@"guest_oid2" + allProfiles:secondAccount.tenantProfiles + hasClaims:YES]; +} + +- (NSInteger)indexOfTenantProfileInArray:(NSArray *)allProfiles + localAccountId:(NSString *)localAccountId +{ + for (MSALTenantProfile *tenantProfile in allProfiles) + { + if ([tenantProfile.identifier isEqualToString:localAccountId]) + { + return [allProfiles indexOfObject:tenantProfile]; + } + } + + return -1; +} + +- (MSALAccount *)accountWithIdentifier:(NSString *)identifier + fromArray:(NSArray *)array +{ + for (MSALAccount *account in array) + { + if ([account.identifier isEqualToString:identifier]) + { + return account; + } + } + + return nil; +} + +- (void)verifyTenantProfileWithIndex:(NSInteger)index + tenantId:(NSString *)tenantId + environment:(NSString *)environment + localAccountId:(NSString *)localAccountId + allProfiles:(NSArray *)allProfiles + hasClaims:(BOOL)hasClaims +{ + XCTAssertTrue(index != -1); + + MSALTenantProfile *profile = allProfiles[index]; + + XCTAssertEqualObjects(profile.tenantId, tenantId); + XCTAssertEqualObjects(profile.environment, environment); + XCTAssertEqualObjects(profile.identifier, localAccountId); + + if (hasClaims) + { + XCTAssertTrue(profile.claims.count > 0); + } + else + { + XCTAssertNil(profile.claims); + } +} + +- (void)testAllAccounts_whenMultipleLegacyAccountsInCache_shouldReturnThem { + MSALAccountsProvider *provider = [[MSALAccountsProvider alloc] initWithTokenCache:defaultCache clientId:@"client_id"]; + + // first user logged in 1 home tenant and 2 guest tenants + [MSIDTestCacheUtil saveLegacyTokensWithAuthority:@"https://login.microsoftonline.com/tid" + clientId:@"client_id" + upn:@"user@contoso.com" + name:@"contoso_user" + uid:@"uid" + utid:@"tid" + oid:@"oid" + tenantId:@"tid" + familyId:nil + cacheAccessor:legacyCache]; + + [MSIDTestCacheUtil saveLegacyTokensWithAuthority:@"https://login.microsoftonline.com/guest_tid" + clientId:@"client_id" + upn:@"user@contoso.com" + name:@"contoso_user" + uid:@"uid" + utid:@"tid" + oid:@"guest_oid" + tenantId:@"guest_tid" + familyId:nil + cacheAccessor:legacyCache]; + + [MSIDTestCacheUtil saveLegacyTokensWithAuthority:@"https://login.microsoftonline.com/guest2_tid" + clientId:@"client_id" + upn:@"user@contoso.com" + name:@"contoso_user" + uid:@"uid" + utid:@"tid" + oid:@"guest2_oid" + tenantId:@"guest2_tid" + familyId:nil + cacheAccessor:legacyCache]; + + // second user logged in 1 home tenant and 1 guest tenant + [MSIDTestCacheUtil saveLegacyTokensWithAuthority:@"https://login.microsoftonline.com/tid2" + clientId:@"client_id" + upn:@"user@fabricant.com" + name:@"fabricant_user" + uid:@"uid2" + utid:@"tid2" + oid:@"oid2" + tenantId:@"tid2" + familyId:nil + cacheAccessor:legacyCache]; + + [MSIDTestCacheUtil saveLegacyTokensWithAuthority:@"https://login.microsoftonline.com/guest_tid2" + clientId:@"client_id" + upn:@"user@fabricant.com" + name:@"fabricant_user" + uid:@"uid2" + utid:@"tid2" + oid:@"guest_oid2" + tenantId:@"guest_tid2" + familyId:nil + cacheAccessor:legacyCache]; + + NSError *error; + NSArray *allAccounts = [provider allAccounts:&error]; + XCTAssertNil(error); + XCTAssertNotNil(allAccounts); + XCTAssertEqual(allAccounts.count, 2); + + // verify first account + MSALAccount *firstAccount = [self accountWithIdentifier:@"uid.tid" fromArray:allAccounts]; + XCTAssertNotNil(firstAccount); + + XCTAssertEqualObjects(firstAccount.username, @"user@contoso.com"); + XCTAssertEqualObjects(firstAccount.homeAccountId.identifier, @"uid.tid"); + XCTAssertEqualObjects(firstAccount.environment, @"login.microsoftonline.com"); + XCTAssertEqualObjects(firstAccount.lookupAccountIdentifier.homeAccountId, @"uid.tid"); + XCTAssertEqualObjects(firstAccount.identifier, @"uid.tid"); + XCTAssertTrue(firstAccount.accountClaims.count > 0); + + // expect 3 tenant profiles + XCTAssertEqual(firstAccount.tenantProfiles.count, 3); + + NSInteger a1FirstProfileIndex = [self indexOfTenantProfileInArray:firstAccount.tenantProfiles localAccountId:@"oid"]; + + [self verifyTenantProfileWithIndex:a1FirstProfileIndex + tenantId:@"tid" + environment:@"login.microsoftonline.com" + localAccountId:@"oid" + allProfiles:firstAccount.tenantProfiles + hasClaims:YES]; + + + NSInteger a1SecondProfileIndex = [self indexOfTenantProfileInArray:firstAccount.tenantProfiles localAccountId:@"guest_oid"]; + + [self verifyTenantProfileWithIndex:a1SecondProfileIndex + tenantId:@"guest_tid" + environment:@"login.microsoftonline.com" + localAccountId:@"guest_oid" + allProfiles:firstAccount.tenantProfiles + hasClaims:YES]; + + NSInteger a1ThirdProfileIndex = [self indexOfTenantProfileInArray:firstAccount.tenantProfiles localAccountId:@"guest2_oid"]; + + [self verifyTenantProfileWithIndex:a1ThirdProfileIndex + tenantId:@"guest2_tid" + environment:@"login.microsoftonline.com" + localAccountId:@"guest2_oid" + allProfiles:firstAccount.tenantProfiles + hasClaims:YES]; + + // verify second account + MSALAccount *secondAccount = [self accountWithIdentifier:@"uid2.tid2" fromArray:allAccounts]; + XCTAssertNotNil(secondAccount); + + XCTAssertEqualObjects(secondAccount.username, @"user@fabricant.com"); + XCTAssertEqualObjects(secondAccount.homeAccountId.identifier, @"uid2.tid2"); + XCTAssertEqualObjects(secondAccount.environment, @"login.microsoftonline.com"); + XCTAssertEqualObjects(secondAccount.lookupAccountIdentifier.homeAccountId, @"uid2.tid2"); + XCTAssertEqualObjects(secondAccount.identifier, @"uid2.tid2"); + XCTAssertTrue(secondAccount.accountClaims.count > 0); + + // expect 2 tenant profiles + XCTAssertEqual(secondAccount.tenantProfiles.count, 2); + + NSInteger a2FirstProfileIndex = [self indexOfTenantProfileInArray:secondAccount.tenantProfiles localAccountId:@"guest_oid2"]; + + [self verifyTenantProfileWithIndex:a2FirstProfileIndex + tenantId:@"guest_tid2" + environment:@"login.microsoftonline.com" + localAccountId:@"guest_oid2" + allProfiles:secondAccount.tenantProfiles + hasClaims:YES]; + + NSInteger a2SecondProfileIndex = [self indexOfTenantProfileInArray:secondAccount.tenantProfiles localAccountId:@"oid2"]; + + [self verifyTenantProfileWithIndex:a2SecondProfileIndex + tenantId:@"tid2" + environment:@"login.microsoftonline.com" + localAccountId:@"oid2" + allProfiles:secondAccount.tenantProfiles + hasClaims:YES]; +} + +- (void)testAllAccounts_whenMixLegacyAccountsAndDefaultAccountsInCache_shouldReturnThemProperly { + MSALAccountsProvider *provider = [[MSALAccountsProvider alloc] initWithTokenCache:defaultCache clientId:@"client_id"]; + + [self setupMixedAccountsInCache]; + + NSError *error; + NSArray *allAccounts = [provider allAccounts:&error]; + XCTAssertNil(error); + XCTAssertNotNil(allAccounts); + XCTAssertEqual(allAccounts.count, 2); + + // verify first account + MSALAccount *firstAccount = [self accountWithIdentifier:@"uid.tid" fromArray:allAccounts]; + XCTAssertNotNil(firstAccount); + + XCTAssertEqualObjects(firstAccount.username, @"user@contoso.com"); + XCTAssertEqualObjects(firstAccount.homeAccountId.identifier, @"uid.tid"); + XCTAssertEqualObjects(firstAccount.environment, @"login.microsoftonline.com"); + XCTAssertEqualObjects(firstAccount.lookupAccountIdentifier.homeAccountId, @"uid.tid"); + XCTAssertEqualObjects(firstAccount.identifier, @"uid.tid"); + XCTAssertTrue(firstAccount.accountClaims.count > 0); + + // expect 3 tenant profiles + XCTAssertEqual(firstAccount.tenantProfiles.count, 3); + + NSInteger a1FirstProfileIndex = [self indexOfTenantProfileInArray:firstAccount.tenantProfiles localAccountId:@"oid"]; + + [self verifyTenantProfileWithIndex:a1FirstProfileIndex + tenantId:@"tid" + environment:@"login.microsoftonline.com" + localAccountId:@"oid" + allProfiles:firstAccount.tenantProfiles + hasClaims:YES]; + + + NSInteger a1SecondProfileIndex = [self indexOfTenantProfileInArray:firstAccount.tenantProfiles localAccountId:@"guest_oid"]; + + [self verifyTenantProfileWithIndex:a1SecondProfileIndex + tenantId:@"guest_tid" + environment:@"login.microsoftonline.com" + localAccountId:@"guest_oid" + allProfiles:firstAccount.tenantProfiles + hasClaims:NO]; + + NSInteger a1ThirdProfileIndex = [self indexOfTenantProfileInArray:firstAccount.tenantProfiles localAccountId:@"guest2_oid"]; + + [self verifyTenantProfileWithIndex:a1ThirdProfileIndex + tenantId:@"guest2_tid" + environment:@"login.microsoftonline.com" + localAccountId:@"guest2_oid" + allProfiles:firstAccount.tenantProfiles + hasClaims:YES]; + + // verify second account + MSALAccount *secondAccount = [self accountWithIdentifier:@"uid2.tid2" fromArray:allAccounts]; + XCTAssertNotNil(secondAccount); + + XCTAssertEqualObjects(secondAccount.username, @"user@fabricant.com"); + XCTAssertEqualObjects(secondAccount.homeAccountId.identifier, @"uid2.tid2"); + XCTAssertEqualObjects(secondAccount.environment, @"login.microsoftonline.com"); + XCTAssertEqualObjects(secondAccount.lookupAccountIdentifier.homeAccountId, @"uid2.tid2"); + + // expect 2 tenant profiles + XCTAssertEqual(secondAccount.tenantProfiles.count, 2); + + NSInteger a2FirstProfileIndex = [self indexOfTenantProfileInArray:secondAccount.tenantProfiles localAccountId:@"oid2"]; + + [self verifyTenantProfileWithIndex:a2FirstProfileIndex + tenantId:@"tid2" + environment:@"login.microsoftonline.com" + localAccountId:@"oid2" + allProfiles:secondAccount.tenantProfiles + hasClaims:YES]; + + + NSInteger a2SecondProfileIndex = [self indexOfTenantProfileInArray:secondAccount.tenantProfiles localAccountId:@"guest_oid2"]; + + [self verifyTenantProfileWithIndex:a2SecondProfileIndex + tenantId:@"guest_tid2" + environment:@"login.microsoftonline.com" + localAccountId:@"guest_oid2" + allProfiles:secondAccount.tenantProfiles + hasClaims:YES]; +} + +- (void)testAccountForHomeAccountId_whenMixLegacyAccountsAndDefaultAccountsInCache_shouldReturnThemProperly { + MSALAccountsProvider *provider = [[MSALAccountsProvider alloc] initWithTokenCache:defaultCache clientId:@"client_id"]; + + [self setupMixedAccountsInCache]; + + NSError *error; + MSALAccountEnumerationParameters *parameters = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:@"uid.tid"]; + MSALAccount *account = [provider accountForParameters:parameters error:&error]; + XCTAssertNil(error); + XCTAssertNotNil(account); + + XCTAssertEqualObjects(account.username, @"user@contoso.com"); + XCTAssertEqualObjects(account.homeAccountId.identifier, @"uid.tid"); + XCTAssertEqualObjects(account.environment, @"login.microsoftonline.com"); + XCTAssertEqualObjects(account.lookupAccountIdentifier.homeAccountId, @"uid.tid"); + XCTAssertEqualObjects(account.identifier, @"uid.tid"); + XCTAssertTrue(account.accountClaims.count > 0); + + // expect 3 tenant profiles + XCTAssertEqual(account.tenantProfiles.count, 3); + + NSInteger a1FirstProfileIndex = [self indexOfTenantProfileInArray:account.tenantProfiles localAccountId:@"oid"]; + + [self verifyTenantProfileWithIndex:a1FirstProfileIndex + tenantId:@"tid" + environment:@"login.microsoftonline.com" + localAccountId:@"oid" + allProfiles:account.tenantProfiles + hasClaims:YES]; + + + NSInteger a1SecondProfileIndex = [self indexOfTenantProfileInArray:account.tenantProfiles localAccountId:@"guest_oid"]; + + [self verifyTenantProfileWithIndex:a1SecondProfileIndex + tenantId:@"guest_tid" + environment:@"login.microsoftonline.com" + localAccountId:@"guest_oid" + allProfiles:account.tenantProfiles + hasClaims:NO]; + + NSInteger a1ThirdProfileIndex = [self indexOfTenantProfileInArray:account.tenantProfiles localAccountId:@"guest2_oid"]; + + [self verifyTenantProfileWithIndex:a1ThirdProfileIndex + tenantId:@"guest2_tid" + environment:@"login.microsoftonline.com" + localAccountId:@"guest2_oid" + allProfiles:account.tenantProfiles + hasClaims:YES]; +} + +- (void)testAccountForUsername_whenMixLegacyAccountsAndDefaultAccountsInCache_shouldReturnThemProperly { + MSALAccountsProvider *provider = [[MSALAccountsProvider alloc] initWithTokenCache:defaultCache clientId:@"client_id"]; + + [self setupMixedAccountsInCache]; + + NSError *error; + MSALAccountEnumerationParameters *parameters = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:nil username:@"user@contoso.com"]; + MSALAccount *account = [provider accountForParameters:parameters error:&error]; + XCTAssertNil(error); + XCTAssertNotNil(account); + + XCTAssertEqualObjects(account.username, @"user@contoso.com"); + XCTAssertEqualObjects(account.homeAccountId.identifier, @"uid.tid"); + XCTAssertEqualObjects(account.environment, @"login.microsoftonline.com"); + XCTAssertEqualObjects(account.lookupAccountIdentifier.homeAccountId, @"uid.tid"); + XCTAssertEqualObjects(account.identifier, @"uid.tid"); + XCTAssertTrue(account.accountClaims.count > 0); + + // expect 3 tenant profiles + XCTAssertEqual(account.tenantProfiles.count, 3); + + NSInteger a1FirstProfileIndex = [self indexOfTenantProfileInArray:account.tenantProfiles localAccountId:@"oid"]; + + [self verifyTenantProfileWithIndex:a1FirstProfileIndex + tenantId:@"tid" + environment:@"login.microsoftonline.com" + localAccountId:@"oid" + allProfiles:account.tenantProfiles + hasClaims:YES]; + + + NSInteger a1SecondProfileIndex = [self indexOfTenantProfileInArray:account.tenantProfiles localAccountId:@"guest_oid"]; + + [self verifyTenantProfileWithIndex:a1SecondProfileIndex + tenantId:@"guest_tid" + environment:@"login.microsoftonline.com" + localAccountId:@"guest_oid" + allProfiles:account.tenantProfiles + hasClaims:NO]; + + NSInteger a1ThirdProfileIndex = [self indexOfTenantProfileInArray:account.tenantProfiles localAccountId:@"guest2_oid"]; + + [self verifyTenantProfileWithIndex:a1ThirdProfileIndex + tenantId:@"guest2_tid" + environment:@"login.microsoftonline.com" + localAccountId:@"guest2_oid" + allProfiles:account.tenantProfiles + hasClaims:YES]; +} + +- (void)testAllAccountsFilteredByAuthority_whenMixLegacyAccountsAndDefaultAccountsInCache_shouldReturnThemProperly { + MSALAccountsProvider *provider = [[MSALAccountsProvider alloc] initWithTokenCache:defaultCache clientId:@"client_id"]; + + // first user logged in 1 home tenant and 2 guest tenants + [MSIDTestCacheUtil saveDefaultTokensWithAuthority:@"https://login.microsoftonline.com/tid" + clientId:@"client_id" + upn:@"user@contoso.com" + name:@"contoso_user" + uid:@"uid" + utid:@"tid" + oid:@"oid" + tenantId:@"tid" + familyId:nil + cacheAccessor:defaultCache]; + + [MSIDTestCacheUtil saveDefaultTokensWithAuthority:@"https://login.microsoftonline.com/guest_tid" + clientId:@"different_client_id" + upn:@"user@contoso.com" + name:@"contoso_user" + uid:@"uid" + utid:@"tid" + oid:@"guest_oid" + tenantId:@"guest_tid" + familyId:nil + cacheAccessor:defaultCache]; + + [MSIDTestCacheUtil saveLegacyTokensWithAuthority:@"https://login.microsoftonline.com/guest2_tid" + clientId:@"client_id" + upn:@"user@contoso.com" + name:@"contoso_user" + uid:@"uid" + utid:@"tid" + oid:@"guest2_oid" + tenantId:@"guest2_tid" + familyId:nil + cacheAccessor:legacyCache]; + + // second user logged in 1 home tenant and 1 guest tenant + [MSIDTestCacheUtil saveLegacyTokensWithAuthority:@"https://login.microsoftonline.de/tid2" + clientId:@"client_id" + upn:@"user@fabricant.com" + name:@"fabricant_user" + uid:@"uid2" + utid:@"tid2" + oid:@"oid2" + tenantId:@"tid2" + familyId:nil + cacheAccessor:legacyCache]; + + [MSIDTestCacheUtil saveDefaultTokensWithAuthority:@"https://login.microsoftonline.de/guest_tid2" + clientId:@"client_id" + upn:@"user@fabricant.com" + name:@"fabricant_user" + uid:@"uid2" + utid:@"tid2" + oid:@"guest_oid2" + tenantId:@"guest_tid2" + familyId:nil + cacheAccessor:defaultCache]; + + // Add mock network response for instance discovery + NSError *error; + NSString *authorityStr = @"https://login.microsoftonline.com/tid"; + MSALAADAuthority *authority = [[MSALAADAuthority alloc] initWithURL:[NSURL URLWithString:authorityStr] error:&error]; + XCTAssertNil(error); + MSIDTestURLResponse *discoveryResponse = [MSIDTestURLResponse discoveryResponseForAuthority:authorityStr]; + [discoveryResponse->_requestHeaders removeObjectForKey:MSID_OAUTH2_CORRELATION_ID_REQUEST_VALUE]; + [discoveryResponse->_requestHeaders removeObjectForKey:MSID_OAUTH2_CORRELATION_ID_REQUEST]; + [discoveryResponse->_requestHeaders removeObjectForKey:MSID_APP_VER_KEY]; + [discoveryResponse->_requestHeaders removeObjectForKey:MSID_APP_NAME_KEY]; + + MSIDTestURLResponse *oidcResponse = + [MSIDTestURLResponse oidcResponseForAuthority:authorityStr + responseUrl:authorityStr + query:nil]; + + [MSIDTestURLSession addResponses:@[discoveryResponse, oidcResponse]]; + + // filter accounts by authority + XCTestExpectation *expectation = [self expectationWithDescription:@"Filter accounts by authority."]; + [provider allAccountsFilteredByAuthority:authority + completionBlock:^(NSArray *accounts, NSError *error) { + XCTAssertNil(error); + XCTAssertNotNil(accounts); + XCTAssertEqual(accounts.count, 1); + + // verify first account + XCTAssertEqualObjects(accounts[0].username, @"user@contoso.com"); + XCTAssertEqualObjects(accounts[0].homeAccountId.identifier, @"uid.tid"); + XCTAssertEqualObjects(accounts[0].environment, @"login.microsoftonline.com"); + XCTAssertEqualObjects(accounts[0].lookupAccountIdentifier.homeAccountId, @"uid.tid"); + + // expect 3 tenant profiles + XCTAssertEqual(accounts[0].tenantProfiles.count, 3); + + NSInteger a1FirstProfileIndex = [self indexOfTenantProfileInArray:accounts[0].tenantProfiles localAccountId:@"oid"]; + + [self verifyTenantProfileWithIndex:a1FirstProfileIndex + tenantId:@"tid" + environment:@"login.microsoftonline.com" + localAccountId:@"oid" + allProfiles:accounts[0].tenantProfiles + hasClaims:YES]; + + + NSInteger a1SecondProfileIndex = [self indexOfTenantProfileInArray:accounts[0].tenantProfiles localAccountId:@"guest_oid"]; + + [self verifyTenantProfileWithIndex:a1SecondProfileIndex + tenantId:@"guest_tid" + environment:@"login.microsoftonline.com" + localAccountId:@"guest_oid" + allProfiles:accounts[0].tenantProfiles + hasClaims:NO]; + + NSInteger a1ThirdProfileIndex = [self indexOfTenantProfileInArray:accounts[0].tenantProfiles localAccountId:@"guest2_oid"]; + + [self verifyTenantProfileWithIndex:a1ThirdProfileIndex + tenantId:@"guest2_tid" + environment:@"login.microsoftonline.com" + localAccountId:@"guest2_oid" + allProfiles:accounts[0].tenantProfiles + hasClaims:YES]; + + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:1 handler:nil]; +} + +- (void)setupMixedAccountsInCache +{ + // first user logged in 1 home tenant and 2 guest tenants + [MSIDTestCacheUtil saveDefaultTokensWithAuthority:@"https://login.microsoftonline.com/tid" + clientId:@"client_id" + upn:@"user@contoso.com" + name:@"contoso_user" + uid:@"uid" + utid:@"tid" + oid:@"oid" + tenantId:@"tid" + familyId:nil + cacheAccessor:defaultCache]; + + [MSIDTestCacheUtil saveDefaultTokensWithAuthority:@"https://login.microsoftonline.com/guest_tid" + clientId:@"different_client_id" + upn:@"user@contoso.com" + name:@"contoso_user" + uid:@"uid" + utid:@"tid" + oid:@"guest_oid" + tenantId:@"guest_tid" + familyId:nil + cacheAccessor:defaultCache]; + + [MSIDTestCacheUtil saveLegacyTokensWithAuthority:@"https://login.microsoftonline.com/guest2_tid" + clientId:@"client_id" + upn:@"user@contoso.com" + name:@"contoso_user" + uid:@"uid" + utid:@"tid" + oid:@"guest2_oid" + tenantId:@"guest2_tid" + familyId:nil + cacheAccessor:legacyCache]; + + // second user logged in 1 home tenant and 1 guest tenant + [MSIDTestCacheUtil saveLegacyTokensWithAuthority:@"https://login.microsoftonline.com/tid2" + clientId:@"client_id" + upn:@"user@fabricant.com" + name:@"fabricant_user" + uid:@"uid2" + utid:@"tid2" + oid:@"oid2" + tenantId:@"tid2" + familyId:nil + cacheAccessor:legacyCache]; + + [MSIDTestCacheUtil saveDefaultTokensWithAuthority:@"https://login.microsoftonline.com/guest_tid2" + clientId:@"client_id" + upn:@"user@fabricant.com" + name:@"fabricant_user" + uid:@"uid2" + utid:@"tid2" + oid:@"guest_oid2" + tenantId:@"guest_tid2" + familyId:nil + cacheAccessor:defaultCache]; +} + +#pragma mark - External accounts + +- (void)testAllAccounts_whenLegacyAccountInCache_andSameExternalAccountExists_shouldReturnOneMergedAccount +{ + MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"uid.tid" objectId:nil tenantId:nil]; + MSALAccount *externalAccount = [[MSALAccount alloc] initWithUsername:@"user@contoso.com" homeAccountId:accountId environment:@"login.microsoftonline.com" tenantProfiles:nil]; + MSALMockExternalAccountHandler *externalAccountsHandler = [[MSALMockExternalAccountHandler alloc] initMock]; + externalAccountsHandler.externalAccountsResult = @[externalAccount]; + + MSALAccountsProvider *provider = [[MSALAccountsProvider alloc] initWithTokenCache:defaultCache + clientId:@"client_id" + externalAccountProvider:externalAccountsHandler]; + + [MSIDTestCacheUtil saveLegacyTokensWithAuthority:@"https://login.microsoftonline.com/tid" + clientId:@"client_id" + upn:@"user@contoso.com" + name:@"simple_user" + uid:@"uid" + utid:@"tid" + oid:@"oid" + tenantId:@"tid" + familyId:nil + cacheAccessor:legacyCache]; + + NSError *error; + NSArray *allAccounts = [provider allAccounts:&error]; + XCTAssertNil(error); + XCTAssertNotNil(allAccounts); + XCTAssertEqual(allAccounts.count, 1); + XCTAssertEqualObjects(allAccounts[0].username, @"user@contoso.com"); + XCTAssertEqualObjects(allAccounts[0].homeAccountId.identifier, @"uid.tid"); + XCTAssertEqualObjects(allAccounts[0].environment, @"login.microsoftonline.com"); + XCTAssertEqualObjects(allAccounts[0].lookupAccountIdentifier.homeAccountId, @"uid.tid"); + XCTAssertEqual(allAccounts[0].tenantProfiles.count, 1); + XCTAssertEqualObjects(allAccounts[0].identifier, @"uid.tid"); + XCTAssertTrue(allAccounts[0].accountClaims.count > 0); + XCTAssertEqualObjects(allAccounts[0].tenantProfiles[0].tenantId, @"tid"); + XCTAssertEqualObjects(allAccounts[0].tenantProfiles[0].environment, @"login.microsoftonline.com"); + XCTAssertEqualObjects(allAccounts[0].tenantProfiles[0].identifier, @"oid"); + XCTAssertEqualObjects(allAccounts[0].tenantProfiles[0].tenantId, @"tid"); + XCTAssertTrue(allAccounts[0].tenantProfiles[0].claims.count > 0); + XCTAssertNotNil([allAccounts[0] accountClaims]); +} + +- (void)testAllAccounts_whenLegacyAccountInCache_andDifferentExternalAccountExists_shouldReturnTwoAccounts +{ + MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"uid2.utid2" objectId:@"uid2" tenantId:@"utid2"]; + + MSALTenantProfile *firstTenantProfile = [[MSALTenantProfile alloc] initWithIdentifier:@"uid2" + tenantId:@"utid2" + environment:@"login.microsoftonline.com" + isHomeTenantProfile:YES + claims:@{@"home":@"claim"}]; + + MSALTenantProfile *secondTenantProfile = [[MSALTenantProfile alloc] initWithIdentifier:@"guestid" + tenantId:@"guesttid" + environment:@"login.microsoftonline.com" + isHomeTenantProfile:NO + claims:@{@"guest": @"claim"}]; + + MSALAccount *externalAccount = [[MSALAccount alloc] initWithUsername:@"user2@contoso.com" + homeAccountId:accountId + environment:@"login.microsoftonline.com" + tenantProfiles:@[firstTenantProfile, secondTenantProfile]]; + + MSALMockExternalAccountHandler *externalAccountsHandler = [[MSALMockExternalAccountHandler alloc] initMock]; + externalAccountsHandler.externalAccountsResult = @[externalAccount]; + + MSALAccountsProvider *provider = [[MSALAccountsProvider alloc] initWithTokenCache:defaultCache + clientId:@"client_id" + externalAccountProvider:externalAccountsHandler]; + + [MSIDTestCacheUtil saveDefaultTokensWithAuthority:@"https://login.microsoftonline.com/tid" + clientId:@"client_id" + upn:@"user@contoso.com" + name:@"simple_user" + uid:@"uid" + utid:@"tid" + oid:@"oid" + tenantId:@"tid" + familyId:nil + cacheAccessor:defaultCache]; + + NSError *error; + NSArray *allAccounts = [provider allAccounts:&error]; + XCTAssertNil(error); + XCTAssertNotNil(allAccounts); + XCTAssertEqual(allAccounts.count, 2); + + // verify first account + MSALAccount *firstAccount = [self accountWithIdentifier:@"uid.tid" fromArray:allAccounts]; + XCTAssertNotNil(firstAccount); + XCTAssertEqualObjects(firstAccount.username, @"user@contoso.com"); + XCTAssertEqualObjects(firstAccount.environment, @"login.microsoftonline.com"); + + // verify external account + MSALAccount *secondAccount = [self accountWithIdentifier:@"uid2.utid2" fromArray:allAccounts]; + XCTAssertNotNil(secondAccount); + XCTAssertEqualObjects(secondAccount.username, @"user2@contoso.com"); + XCTAssertEqualObjects(secondAccount.environment, @"login.microsoftonline.com"); + XCTAssertEqualObjects(secondAccount.accountClaims, @{@"home":@"claim"}); +} + +@end diff --git a/MSAL/test/unit/MSALAcquireTokenTests.m b/MSAL/test/unit/MSALAcquireTokenTests.m index 1cc49edd31..0591179f49 100644 --- a/MSAL/test/unit/MSALAcquireTokenTests.m +++ b/MSAL/test/unit/MSALAcquireTokenTests.m @@ -75,12 +75,16 @@ #import "MSIDTestURLResponse+Util.h" #import "MSIDVersion.h" #import "MSIDConstants.h" +#import "MSALTenantProfile.h" #import "MSALClaimsRequest.h" +#import "MSALAccountId+Internal.h" +#import "MSIDAccountMetadataCacheAccessor.h" @interface MSALAcquireTokenTests : MSALTestCase @property (nonatomic) MSIDDefaultTokenCacheAccessor *tokenCache; @property (nonatomic) MSIDAccountCredentialCache *accountCache; +@property (nonatomic) MSIDAccountMetadataCacheAccessor *accountMetadataCache; @end @@ -90,7 +94,7 @@ - (void)setUp { [super setUp]; - id dataSource; + id dataSource; #if TARGET_OS_IPHONE dataSource = MSIDKeychainTokenCache.defaultKeychainCache; #else @@ -98,8 +102,10 @@ - (void)setUp #endif self.tokenCache = [[MSIDDefaultTokenCacheAccessor alloc] initWithDataSource:dataSource otherCacheAccessors:nil]; self.accountCache = [[MSIDAccountCredentialCache alloc] initWithDataSource:dataSource]; + self.accountMetadataCache = [[MSIDAccountMetadataCacheAccessor alloc] initWithDataSource:dataSource]; [self.accountCache clearWithContext:nil error:nil]; [self.tokenCache clearWithContext:nil error:nil]; + MSIDAADNetworkConfiguration.defaultConfiguration.aadApiVersion = @"v2.0"; } @@ -151,6 +157,7 @@ - (void)testAcquireTokenInteractive_whenB2CAuthority_shouldCacheTokens XCTAssertNotNil(application); XCTAssertNil(error); +// application.accountMetadataCache = self.accountMetadataCache; application.webviewType = MSALWebviewTypeWKWebView; // Add authorities to cache @@ -188,7 +195,12 @@ - (void)testAcquireTokenInteractive_whenB2CAuthority_shouldCacheTokens // Now test that we're able to retrieve cache successfully back XCTestExpectation *silentExpectation = [self expectationWithDescription:@"acquireTokenSilentForScopes"]; - +// +// // Save account metadata authority map from common to the specific tenant id. +// [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:@"https://login.microsoftonline.com/tfp/1234-5678-90abcdefg/b2c_1_policy"] +// forRequestURL:authority.url +// homeAccountId:resultAccount.identifier clientId:UNIT_TEST_CLIENT_ID context:nil error:nil]; +// [application acquireTokenSilentForScopes:@[@"fakeb2cscopes"] account:resultAccount completionBlock:^(MSALResult *result, NSError *error) { @@ -280,12 +292,12 @@ - (void)testAcquireTokenSilent_whenNoATForScopeInCache_andInvalidRT_shouldReturn utid:DEFAULT_TEST_UTID familyId:nil]; + MSALAccountId *accountID = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"preferredUserName" - name:@"user@contoso.com" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountID environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; // Add AT & RT. MSIDConfiguration *configuration = [MSIDTestConfiguration v2DefaultConfiguration]; @@ -297,17 +309,22 @@ - (void)testAcquireTokenSilent_whenNoATForScopeInCache_andInvalidRT_shouldReturn error:nil]; XCTAssertTrue(result); + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:authority] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountID.identifier clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; + NSError *error = nil; MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] initWithClientId:UNIT_TEST_CLIENT_ID error:&error]; XCTAssertNotNil(application); application.tokenCache = self.tokenCache; + application.accountMetadataCache = self.accountMetadataCache; // Set up the network responses for OIDC discovery and the RT response NSOrderedSet *expectedScopes = [NSOrderedSet orderedSetWithArray:@[@"mail.read", @"openid", @"profile", @"offline_access"]]; - MSIDTestURLResponse *tokenResponse = [MSIDTestURLResponse errorRtResponseForScopes:expectedScopes authority:authority tenantId:nil account:account errorCode:@"invalid_grant" errorDescription:@"Refresh token revoked" subError:@"unauthorized_client" claims:nil refreshToken:nil]; + MSIDTestURLResponse *tokenResponse = [MSIDTestURLResponse errorRtResponseForScopes:expectedScopes authority:authority tenantId:@"1234-5678-90abcdefg" account:account errorCode:@"invalid_grant" errorDescription:@"Refresh token revoked" subError:@"unauthorized_client" claims:nil refreshToken:nil]; [MSIDTestURLSession addResponses:@[tokenResponse]]; // Acquire a token silently for a scope that does not exist in cache @@ -349,12 +366,12 @@ - (void)testAcquireTokenSilent_whenNoATForScopeInCache_shouldUseRTAndReturnNewAT utid:DEFAULT_TEST_UTID familyId:nil]; + MSALAccountId *accountID = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"preferredUserName" - name:@"user@contoso.com" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountID environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; // Add AT & RT. MSIDConfiguration *configuration = [MSIDTestConfiguration v2DefaultConfiguration]; @@ -366,17 +383,22 @@ - (void)testAcquireTokenSilent_whenNoATForScopeInCache_shouldUseRTAndReturnNewAT error:nil]; XCTAssertTrue(result); + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:authority] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountID.identifier clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; + NSError *error = nil; MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] initWithClientId:UNIT_TEST_CLIENT_ID error:&error]; XCTAssertNotNil(application); application.tokenCache = self.tokenCache; + application.accountMetadataCache = self.accountMetadataCache; MSALGlobalConfig.brokerAvailability = MSALBrokeredAvailabilityNone; // Set up the network responses for OIDC discovery and the RT response NSOrderedSet *expectedScopes = [NSOrderedSet orderedSetWithArray:@[@"mail.read", @"openid", @"profile", @"offline_access"]]; - MSIDTestURLResponse *tokenResponse = [MSIDTestURLResponse rtResponseForScopes:expectedScopes authority:authority tenantId:nil user:account claims:nil]; + MSIDTestURLResponse *tokenResponse = [MSIDTestURLResponse rtResponseForScopes:expectedScopes authority:authority tenantId:@"1234-5678-90abcdefg" uid:@"1" user:account claims:nil]; NSMutableDictionary *json = [[response jsonDictionary] mutableCopy]; json[@"access_token"] = @"i am an updated access token!"; json[@"scope"] = [expectedScopes msidToString]; @@ -443,7 +465,6 @@ - (void)testAcquireTokenInteractive_whenClaimsIsPassedViaOverloadedAcquireToken_ @"client-request-id" : [MSIDTestRequireValueSentinel sentinel], @"return-client-request-id" : @"true", @"state" : [MSIDTestRequireValueSentinel sentinel], - @"prompt" : @"select_account", @"client_id" : UNIT_TEST_CLIENT_ID, @"scope" : @"fakescopes openid profile offline_access", @"client_info" : @"1", @@ -666,7 +687,6 @@ - (void)testAcquireTokenInteractive_whenCapabilitiesSet_shouldSendCapabilitiesTo @"client-request-id" : [MSIDTestRequireValueSentinel sentinel], @"return-client-request-id" : @"true", @"state" : [MSIDTestRequireValueSentinel sentinel], - @"prompt" : @"select_account", @"client_id" : UNIT_TEST_CLIENT_ID, @"scope" : @"fakescopes openid profile offline_access", @"client_info" : @"1", @@ -765,7 +785,6 @@ - (void)testAcquireTokenInteractive_whenClaimsIsPassedAndCapabilitiesSet_shouldS @"client-request-id" : [MSIDTestRequireValueSentinel sentinel], @"return-client-request-id" : @"true", @"state" : [MSIDTestRequireValueSentinel sentinel], - @"prompt" : @"select_account", @"client_id" : UNIT_TEST_CLIENT_ID, @"scope" : @"fakescopes openid profile offline_access", @"client_info" : @"1", @@ -960,7 +979,6 @@ - (void)testAcquireTokenInteractive_whenInstanceAware_shouldReturnCloudAuthority @"client-request-id" : [MSIDTestRequireValueSentinel sentinel], @"return-client-request-id" : @"true", @"state" : [MSIDTestRequireValueSentinel sentinel], - @"prompt" : @"select_account", @"client_id" : UNIT_TEST_CLIENT_ID, @"scope" : @"fakescopes openid profile offline_access", @"client_info" : @"1", @@ -1061,12 +1079,11 @@ - (void)testAcquireTokenSilent_whenExtendedLifetimeTokenEnabledAndServiceUnavail [json setValue:@"-1" forKey:MSID_OAUTH2_EXPIRES_IN]; MSIDAADV2TokenResponse *response = [[MSIDAADV2TokenResponse alloc] initWithJSONDictionary:json error:nil]; - MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"preferredUserName" - name:@"user@contoso.com" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + MSALAccountId *accountID = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"user@contoso.com" + homeAccountId:accountID environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; MSIDConfiguration *configuration = [MSIDTestConfiguration v2DefaultConfiguration]; configuration.clientId = UNIT_TEST_CLIENT_ID; @@ -1079,13 +1096,18 @@ - (void)testAcquireTokenSilent_whenExtendedLifetimeTokenEnabledAndServiceUnavail // Set up the network responses for OIDC discovery NSString *authority = @"https://login.microsoftonline.com/1234-5678-90abcdefg"; + + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:authority] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountID.identifier clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; + MSIDTestURLResponse *discoveryResponse = [MSIDTestURLResponse discoveryResponseForAuthority:authority]; NSOrderedSet *expectedScopes = [NSOrderedSet orderedSetWithArray:@[@"user.read", @"openid", @"profile", @"offline_access"]]; MSIDTestURLResponse *oidcResponse = [MSIDTestURLResponse oidcResponseForAuthority:authority]; [MSIDTestURLSession addResponses:@[discoveryResponse, oidcResponse]]; // Set up two 504 network responses - MSIDTestURLResponse *tokenResponse = [MSIDTestURLResponse rtResponseForScopes:expectedScopes authority:authority tenantId:nil user:account claims:nil]; + MSIDTestURLResponse *tokenResponse = [MSIDTestURLResponse rtResponseForScopes:expectedScopes authority:authority tenantId:@"1234-5678-90abcdefg" uid:@"1" user:account claims:nil]; [tokenResponse setResponseURL:@"https://someresponseurl.com" code:504 headerFields:@{}]; [MSIDTestURLSession addResponse:tokenResponse]; //Add the responsce twice because retry will happen [MSIDTestURLSession addResponse:tokenResponse]; @@ -1098,6 +1120,7 @@ - (void)testAcquireTokenSilent_whenExtendedLifetimeTokenEnabledAndServiceUnavail MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] initWithConfiguration:config error:&error]; XCTAssertNotNil(application); application.tokenCache = self.tokenCache; + application.accountMetadataCache = self.accountMetadataCache; XCTestExpectation *expectation = [self expectationWithDescription:@"acquireTokenSilentForScopes"]; [application acquireTokenSilentForScopes:@[@"user.read"] @@ -1132,12 +1155,13 @@ - (void)testAcquireTokenSilent_whenExtendedLifetimeTokenDisabledAndServiceUnavai familyId:nil].jsonDictionary.mutableCopy; [json setValue:@"-1" forKey:MSID_OAUTH2_EXPIRES_IN]; MSIDAADV2TokenResponse *response = [[MSIDAADV2TokenResponse alloc] initWithJSONDictionary:json error:nil]; + + MSALAccountId *accountID = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"preferredUserName" - name:@"user@contoso.com" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountID environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; MSIDConfiguration *configuration = [MSIDTestConfiguration v2DefaultConfiguration]; configuration.clientId = UNIT_TEST_CLIENT_ID; @@ -1147,7 +1171,7 @@ - (void)testAcquireTokenSilent_whenExtendedLifetimeTokenDisabledAndServiceUnavai context:nil error:nil]; XCTAssertTrue(result); - + // Set up the network responses for OIDC discovery NSString *authority = @"https://login.microsoftonline.com/1234-5678-90abcdefg"; MSIDTestURLResponse *discoveryResponse = [MSIDTestURLResponse discoveryResponseForAuthority:authority]; @@ -1155,8 +1179,13 @@ - (void)testAcquireTokenSilent_whenExtendedLifetimeTokenDisabledAndServiceUnavai MSIDTestURLResponse *oidcResponse = [MSIDTestURLResponse oidcResponseForAuthority:authority]; [MSIDTestURLSession addResponses:@[discoveryResponse, oidcResponse]]; + + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:authority] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountID.identifier clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; + // Set up two 504 network responses - MSIDTestURLResponse *tokenResponse = [MSIDTestURLResponse rtResponseForScopes:expectedScopes authority:authority tenantId:nil user:account claims:nil]; + MSIDTestURLResponse *tokenResponse = [MSIDTestURLResponse rtResponseForScopes:expectedScopes authority:authority tenantId:@"1234-5678-90abcdefg" uid:@"1" user:account claims:nil]; [tokenResponse setResponseURL:@"https://someresponseurl.com" code:504 headerFields:@{}]; [MSIDTestURLSession addResponse:tokenResponse]; //Add the responsce twice because retry will happen [MSIDTestURLSession addResponse:tokenResponse]; @@ -1169,6 +1198,7 @@ - (void)testAcquireTokenSilent_whenExtendedLifetimeTokenDisabledAndServiceUnavai MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] initWithConfiguration:config error:&error]; XCTAssertNotNil(application); application.tokenCache = self.tokenCache; + application.accountMetadataCache = self.accountMetadataCache; XCTestExpectation *expectation = [self expectationWithDescription:@"acquireTokenSilentForScopes"]; [application acquireTokenSilentForScopes:@[@"user.read"] @@ -1191,6 +1221,7 @@ - (void)testAcquireTokenSilent_whenExtendedLifetimeTokenDisabledAndServiceUnavai - (void)testAcquireTokenSilent_whenATAvailable_andMixedCaseInputScope_shouldReturnToken { + [MSALTestBundle overrideBundleId:@"com.microsoft.unittests"]; NSArray* override = @[ @{ @"CFBundleURLSchemes" : @[UNIT_TEST_DEFAULT_REDIRECT_SCHEME] } ]; [MSALTestBundle overrideObject:override forKey:@"CFBundleURLTypes"]; @@ -1204,12 +1235,13 @@ - (void)testAcquireTokenSilent_whenATAvailable_andMixedCaseInputScope_shouldRetu utid:DEFAULT_TEST_UTID familyId:nil].jsonDictionary.mutableCopy; MSIDAADV2TokenResponse *response = [[MSIDAADV2TokenResponse alloc] initWithJSONDictionary:json error:nil]; - MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"preferredUserName" - name:@"user@contoso.com" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + + MSALAccountId *accountID = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; + + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"user@contoso.com" + homeAccountId:accountID environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; MSIDConfiguration *configuration = [MSIDTestConfiguration v2DefaultConfiguration]; configuration.clientId = UNIT_TEST_CLIENT_ID; @@ -1221,6 +1253,12 @@ - (void)testAcquireTokenSilent_whenATAvailable_andMixedCaseInputScope_shouldRetu XCTAssertTrue(result); NSString *authority = @"https://login.microsoftonline.com/1234-5678-90abcdefg"; + + + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:authority] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountID.identifier clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; + MSIDTestURLResponse *discoveryResponse = [MSIDTestURLResponse discoveryResponseForAuthority:authority]; [MSIDTestURLSession addResponse:discoveryResponse]; @@ -1229,6 +1267,7 @@ - (void)testAcquireTokenSilent_whenATAvailable_andMixedCaseInputScope_shouldRetu error:&error]; XCTAssertNotNil(application); application.tokenCache = self.tokenCache; + application.accountMetadataCache = self.accountMetadataCache; XCTestExpectation *expectation = [self expectationWithDescription:@"acquireTokenSilentForScopes"]; [application acquireTokenSilentForScopes:@[@"USeR.reAD"] @@ -1264,12 +1303,13 @@ - (void)testAcquireTokenSilent_whenATAvailableAndExpired_andMixedCaseInputScope_ [json setValue:@"-1" forKey:MSID_OAUTH2_EXPIRES_IN];//expire the AT MSIDAADV2TokenResponse *response = [[MSIDAADV2TokenResponse alloc] initWithJSONDictionary:json error:nil]; + + MSALAccountId *accountID = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"preferredUserName" - name:@"user@contoso.com" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountID environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; MSIDConfiguration *configuration = [MSIDTestConfiguration v2DefaultConfiguration]; configuration.clientId = UNIT_TEST_CLIENT_ID; @@ -1284,10 +1324,17 @@ - (void)testAcquireTokenSilent_whenATAvailableAndExpired_andMixedCaseInputScope_ NSString *authority = @"https://login.microsoftonline.com/1234-5678-90abcdefg"; MSIDTestURLResponse *discoveryResponse = [MSIDTestURLResponse discoveryResponseForAuthority:authority]; NSOrderedSet *expectedScopes = [NSOrderedSet orderedSetWithArray:@[@"USeR.reAD", @"openid", @"profile", @"offline_access"]]; + + + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:authority] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountID.identifier clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; + // Set up a 200 network responses MSIDTestURLResponse *tokenResponse = [MSIDTestURLResponse rtResponseForScopes:expectedScopes authority:authority - tenantId:nil + tenantId:@"1234-5678-90abcdefg" + uid:@"1" user:account claims:nil]; @@ -1302,6 +1349,7 @@ - (void)testAcquireTokenSilent_whenATAvailableAndExpired_andMixedCaseInputScope_ error:&error]; XCTAssertNotNil(application); application.tokenCache = self.tokenCache; + application.accountMetadataCache = self.accountMetadataCache; XCTestExpectation *expectation = [self expectationWithDescription:@"acquireTokenSilentForScopes"]; [application acquireTokenSilentForScopes:@[@"USeR.reAD"] @@ -1337,12 +1385,12 @@ - (void)testAcquireTokenSilent_whenATAvailableAndExtendedLifetimeTokenEnabled_sh utid:DEFAULT_TEST_UTID familyId:nil].jsonDictionary.mutableCopy; MSIDAADV2TokenResponse *response = [[MSIDAADV2TokenResponse alloc] initWithJSONDictionary:json error:nil]; - MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"preferredUserName" - name:@"user@contoso.com" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + + MSALAccountId *accountID = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"user@contoso.com" + homeAccountId:accountID environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; MSIDConfiguration *configuration = [MSIDTestConfiguration v2DefaultConfiguration]; configuration.clientId = UNIT_TEST_CLIENT_ID; @@ -1352,6 +1400,7 @@ - (void)testAcquireTokenSilent_whenATAvailableAndExtendedLifetimeTokenEnabled_sh context:nil error:nil]; XCTAssertTrue(result); + // Set up the network responses for OIDC discovery NSString *authority = @"https://login.microsoftonline.com/1234-5678-90abcdefg"; @@ -1360,8 +1409,12 @@ - (void)testAcquireTokenSilent_whenATAvailableAndExtendedLifetimeTokenEnabled_sh MSIDTestURLResponse *oidcResponse = [MSIDTestURLResponse oidcResponseForAuthority:authority]; [MSIDTestURLSession addResponses:@[discoveryResponse, oidcResponse]]; + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:authority] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountID.identifier clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; + // Set up two 504 network responses - MSIDTestURLResponse *tokenResponse = [MSIDTestURLResponse rtResponseForScopes:expectedScopes authority:authority tenantId:nil user:account claims:nil]; + MSIDTestURLResponse *tokenResponse = [MSIDTestURLResponse rtResponseForScopes:expectedScopes authority:authority tenantId:@"1234-5678-90abcdefg" uid:@"1" user:account claims:nil]; [tokenResponse setResponseURL:@"https://someresponseurl.com" code:504 headerFields:@{}]; [MSIDTestURLSession addResponse:tokenResponse]; //Add the responsce twice because retry will happen [MSIDTestURLSession addResponse:tokenResponse]; @@ -1375,6 +1428,7 @@ - (void)testAcquireTokenSilent_whenATAvailableAndExtendedLifetimeTokenEnabled_sh MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] initWithConfiguration:config error:&error]; XCTAssertNotNil(application); application.tokenCache = self.tokenCache; + application.accountMetadataCache = self.accountMetadataCache; XCTestExpectation *expectation = [self expectationWithDescription:@"acquireTokenSilentForScopes"]; [application acquireTokenSilentForScopes:@[@"user.read"] @@ -1489,12 +1543,12 @@ - (void)testAcquireTokenSilent_whenInsufficientScopesReturned_shouldReturnNilRes utid:DEFAULT_TEST_UTID familyId:nil].jsonDictionary.mutableCopy; MSIDAADV2TokenResponse *response = [[MSIDAADV2TokenResponse alloc] initWithJSONDictionary:json error:nil]; + + MSALAccountId *accountID = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"preferredUserName" - name:@"user@contoso.com" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountID environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; MSIDConfiguration *configuration = [MSIDTestConfiguration v2DefaultConfiguration]; configuration.clientId = UNIT_TEST_CLIENT_ID; @@ -1514,6 +1568,10 @@ - (void)testAcquireTokenSilent_whenInsufficientScopesReturned_shouldReturnNilRes responseUrl:@"https://login.microsoftonline.com/1234-5678-90abcdefg" query:nil]; + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:@"https://login.microsoftonline.com/1234-5678-90abcdefg"] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountID.identifier clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; + // Mock token response [MSIDTestURLSession addResponse:oidcResponse]; [self addTestTokenResponseWithResponseScopes:@"user.read fakescope1 additional.scope additional.scope2" @@ -1529,6 +1587,7 @@ - (void)testAcquireTokenSilent_whenInsufficientScopesReturned_shouldReturnNilRes MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] initWithClientId:UNIT_TEST_CLIENT_ID authority:[DEFAULT_TEST_AUTHORITY msalAuthority] error:&error]; + application.accountMetadataCache = self.accountMetadataCache; XCTAssertNotNil(application); XCTAssertNil(error); @@ -1591,17 +1650,17 @@ - (void)testAcquireTokenSilent_whenClaimsIsPassed_shouldSkipAtAndUseRt // Add mock response for refresh token grant, claims should be in the request body NSString *claims = @"{\"access_token\":{\"polids\":{\"values\":[\"5ce770ea-8690-4747-aa73-c5b3cd509cd4\"],\"essential\":true}}}"; __auto_type claimsRequest = [[MSALClaimsRequest alloc] initWithJsonString:claims error:nil]; + MSALAccountId *accountID = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"preferredUserName" - name:@"user@contoso.com" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountID environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; NSOrderedSet *expectedScopes = [NSOrderedSet orderedSetWithArray:@[@"user.read", @"openid", @"profile", @"offline_access"]]; MSIDTestURLResponse *tokenResponse = [MSIDTestURLResponse rtResponseForScopes:expectedScopes authority:authority - tenantId:nil + tenantId:@"1234-5678-90abcdefg" + uid:@"1" user:account claims:claims]; NSMutableDictionary *json = [[response jsonDictionary] mutableCopy]; @@ -1610,6 +1669,10 @@ - (void)testAcquireTokenSilent_whenClaimsIsPassed_shouldSkipAtAndUseRt [tokenResponse setResponseJSON:json]; [MSIDTestURLSession addResponses:@[tokenResponse]]; + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:authority] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountID.identifier clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; + // Acquire a token silently NSError *error = nil; MSALPublicClientApplication *application = @@ -1617,6 +1680,7 @@ - (void)testAcquireTokenSilent_whenClaimsIsPassed_shouldSkipAtAndUseRt error:&error]; XCTAssertNotNil(application); application.tokenCache = self.tokenCache; + application.accountMetadataCache = self.accountMetadataCache; XCTestExpectation *expectation = [self expectationWithDescription:@"acquireTokenSilentForScopes"]; [application acquireTokenSilentForScopes:@[@"user.read"] @@ -1679,13 +1743,20 @@ - (void)testAcquireTokenSilent_whenClaimsEmpty_shouldNotSkipAccessToken [[MSALPublicClientApplication alloc] initWithConfiguration:config error:&error]; XCTAssertNotNil(application); application.tokenCache = self.tokenCache; + application.accountMetadataCache = self.accountMetadataCache; - MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"preferredUserName" - name:@"user@contoso.com" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + MSALAccountId *accountID = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; + + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"user@contoso.com" + homeAccountId:accountID environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; + + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:authority] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountID.identifier clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; + + XCTestExpectation *expectation = [self expectationWithDescription:@"acquireTokenSilentForScopes"]; [application acquireTokenSilentForScopes:@[@"user.read"] account:account @@ -1746,13 +1817,19 @@ - (void)testAcquireTokenSilent_whenCapabilitiesSet_shouldNotSkipAccessToken [[MSALPublicClientApplication alloc] initWithConfiguration:config error:&error]; XCTAssertNotNil(application); application.tokenCache = self.tokenCache; + application.accountMetadataCache = self.accountMetadataCache; - MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"preferredUserName" - name:@"user@contoso.com" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + MSALAccountId *accountID = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; + + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"user@contoso.com" + homeAccountId:accountID environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; + + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:authority] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountID.identifier clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; + XCTestExpectation *expectation = [self expectationWithDescription:@"acquireTokenSilentForScopes"]; [application acquireTokenSilentForScopes:@[@"user.read"] account:account @@ -1808,17 +1885,17 @@ - (void)testAcquireTokenSilent_whenCapabilitiesSetAndExpiredAt_shouldSendCapabil // Add mock response for refresh token grant, claims should be in the request body NSString *expectedClaims = @"{\"access_token\":{\"xms_cc\":{\"values\":[\"cp1\",\"llt\"]}}}"; + MSALAccountId *accountID = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"preferredUserName" - name:@"user@contoso.com" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountID environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; NSOrderedSet *expectedScopes = [NSOrderedSet orderedSetWithArray:@[@"user.read", @"openid", @"profile", @"offline_access"]]; MSIDTestURLResponse *tokenResponse = [MSIDTestURLResponse rtResponseForScopes:expectedScopes authority:authority - tenantId:nil + tenantId:@"1234-5678-90abcdefg" + uid:@"1" user:account claims:expectedClaims]; NSMutableDictionary *responseJson = [[response jsonDictionary] mutableCopy]; @@ -1837,6 +1914,11 @@ - (void)testAcquireTokenSilent_whenCapabilitiesSetAndExpiredAt_shouldSendCapabil [[MSALPublicClientApplication alloc] initWithConfiguration:config error:&error]; XCTAssertNotNil(application); application.tokenCache = self.tokenCache; + application.accountMetadataCache = self.accountMetadataCache; + + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:authority] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountID.identifier clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; XCTestExpectation *expectation = [self expectationWithDescription:@"acquireTokenSilentForScopes"]; [application acquireTokenSilentForScopes:@[@"user.read"] @@ -1893,17 +1975,17 @@ - (void)testAcquireTokenSilent_whenClaimsIsPassedAndCapabilitiesSet_shouldSkipAt NSString *claims = @"{\"access_token\":{\"polids\":{\"values\":[\"5ce770ea-8690-4747-aa73-c5b3cd509cd4\"],\"essential\":true}}}"; __auto_type claimsRequest = [[MSALClaimsRequest alloc] initWithJsonString:claims error:nil]; NSString *expectedClaims = @"{\"access_token\":{\"polids\":{\"values\":[\"5ce770ea-8690-4747-aa73-c5b3cd509cd4\"],\"essential\":true},\"xms_cc\":{\"values\":[\"llt\"]}}}"; + MSALAccountId *accountID = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"preferredUserName" - name:@"user@contoso.com" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountID environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; NSOrderedSet *expectedScopes = [NSOrderedSet orderedSetWithArray:@[@"user.read", @"openid", @"profile", @"offline_access"]]; MSIDTestURLResponse *tokenResponse = [MSIDTestURLResponse rtResponseForScopes:expectedScopes authority:authority - tenantId:nil + tenantId:@"1234-5678-90abcdefg" + uid:@"1" user:account claims:expectedClaims]; NSMutableDictionary *json = [[response jsonDictionary] mutableCopy]; @@ -1922,6 +2004,10 @@ - (void)testAcquireTokenSilent_whenClaimsIsPassedAndCapabilitiesSet_shouldSkipAt [[MSALPublicClientApplication alloc] initWithConfiguration:config error:&error]; XCTAssertNotNil(application); application.tokenCache = self.tokenCache; + application.accountMetadataCache = self.accountMetadataCache; + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:authority] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountID.identifier clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; XCTestExpectation *expectation = [self expectationWithDescription:@"acquireTokenSilentForScopes"]; [application acquireTokenSilentForScopes:@[@"user.read"] @@ -1977,12 +2063,11 @@ - (void)testAcquireTokenSilent_whenClaimsIsPassedAndInvalidRt_shouldReturnIntera // Add mock error response for refresh token grant NSString *claims = @"{\"access_token\":{\"polids\":{\"values\":[\"5ce770ea-8690-4747-aa73-c5b3cd509cd4\"],\"essential\":true}}}"; __auto_type claimsRequest = [[MSALClaimsRequest alloc] initWithJsonString:claims error:nil]; + MSALAccountId *accountID = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"preferredUserName" - name:@"user@contoso.com" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountID environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; NSOrderedSet *expectedScopes = [NSOrderedSet orderedSetWithArray:@[@"user.read", @"openid", @"profile", @"offline_access"]]; MSIDTestURLResponse *tokenResponse = [MSIDTestURLResponse errorRtResponseForScopes:expectedScopes @@ -2003,6 +2088,11 @@ - (void)testAcquireTokenSilent_whenClaimsIsPassedAndInvalidRt_shouldReturnIntera error:&error]; XCTAssertNotNil(application); application.tokenCache = self.tokenCache; + application.accountMetadataCache = self.accountMetadataCache; + + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:authority] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountID.identifier clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; XCTestExpectation *expectation = [self expectationWithDescription:@"acquireTokenSilentForScopes"]; [application acquireTokenSilentForScopes:@[@"user.read"] @@ -2044,12 +2134,11 @@ - (void)testAcquireTokenSilent_whenATExpiredAndFRTInCache_shouldRefreshAccessTok [json setObject:@"-3600" forKey:MSID_OAUTH2_EXPIRES_IN]; MSIDAADV2TokenResponse *response = [[MSIDAADV2TokenResponse alloc] initWithJSONDictionary:json error:nil]; + MSALAccountId *accountID = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"preferredUserName" - name:@"user@contoso.com" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountID environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; MSIDConfiguration *configuration = [MSIDTestConfiguration v2DefaultConfiguration]; @@ -2068,7 +2157,8 @@ - (void)testAcquireTokenSilent_whenATExpiredAndFRTInCache_shouldRefreshAccessTok // Set up a 200 network responses MSIDTestURLResponse *tokenResponse = [MSIDTestURLResponse rtResponseForScopes:expectedScopes authority:authority - tenantId:nil + tenantId:@"1234-5678-90abcdefg" + uid:@"1" user:account claims:nil]; [tokenResponse setResponseURL:@"https://someresponseurl.com" code:200 headerFields:@{}]; @@ -2081,6 +2171,12 @@ - (void)testAcquireTokenSilent_whenATExpiredAndFRTInCache_shouldRefreshAccessTok error:&error]; XCTAssertNotNil(application); application.tokenCache = self.tokenCache; + application.accountMetadataCache = self.accountMetadataCache; + + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:authority] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountID.identifier clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; + [self removeRefreshTokenFromCache]; XCTestExpectation *expectation = [self expectationWithDescription:@"acquireTokenSilentForScopes"]; @@ -2115,12 +2211,11 @@ - (void)testAcquireTokenSilent_whenATExpiredAndNoAppMetadataInCacheAndFRTInCache [json setObject:@"-3600" forKey:MSID_OAUTH2_EXPIRES_IN]; MSIDAADV2TokenResponse *response = [[MSIDAADV2TokenResponse alloc] initWithJSONDictionary:json error:nil]; + MSALAccountId *accountID = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"preferredUserName" - name:@"user@contoso.com" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountID environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; MSIDConfiguration *configuration = [MSIDTestConfiguration v2DefaultConfiguration]; configuration.clientId = UNIT_TEST_CLIENT_ID; @@ -2139,7 +2234,8 @@ - (void)testAcquireTokenSilent_whenATExpiredAndNoAppMetadataInCacheAndFRTInCache // Set up a 200 network responses MSIDTestURLResponse *tokenResponse = [MSIDTestURLResponse rtResponseForScopes:expectedScopes authority:authority - tenantId:nil + tenantId:@"1234-5678-90abcdefg" + uid:@"1" user:account claims:nil]; @@ -2153,6 +2249,12 @@ - (void)testAcquireTokenSilent_whenATExpiredAndNoAppMetadataInCacheAndFRTInCache error:&error]; XCTAssertNotNil(application); application.tokenCache = self.tokenCache; + application.accountMetadataCache = self.accountMetadataCache; + + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:authority] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountID.identifier clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; + [self removeRefreshTokenFromCache]; NSArray *metadataEntries = [self.tokenCache getAppMetadataEntries:configuration @@ -2202,12 +2304,11 @@ - (void)testAcquireTokenSilent_whenFRTUsedAndServerReturnsClientMismatch_shouldU utid:DEFAULT_TEST_UTID familyId:@"1"]; + MSALAccountId *accountID = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"preferredUserName" - name:@"user@contoso.com" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountID environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; // Add AT, RT & FRT MSIDConfiguration *configuration = [MSIDTestConfiguration v2DefaultConfiguration]; @@ -2225,6 +2326,11 @@ - (void)testAcquireTokenSilent_whenFRTUsedAndServerReturnsClientMismatch_shouldU error:&error]; XCTAssertNotNil(application); application.tokenCache = self.tokenCache; + application.accountMetadataCache = self.accountMetadataCache; + + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:authority] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountID.identifier clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; [self removeRefreshTokenFromCache]; NSArray *metadataEntries = [self.tokenCache getAppMetadataEntries:configuration @@ -2292,12 +2398,11 @@ - (void)testAcquireTokenSilent_whenFRTUsedAndServerReturnsInvalidGrant_ShouldUse [json setObject:@"-3600" forKey:MSID_OAUTH2_EXPIRES_IN]; MSIDAADV2TokenResponse *response = [[MSIDAADV2TokenResponse alloc] initWithJSONDictionary:json error:nil]; + MSALAccountId *accountID = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"preferredUserName" - name:@"user@contoso.com" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountID environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; MSIDConfiguration *configuration = [MSIDTestConfiguration v2DefaultConfiguration]; @@ -2325,7 +2430,8 @@ - (void)testAcquireTokenSilent_whenFRTUsedAndServerReturnsInvalidGrant_ShouldUse // Set up a 200 network responses MSIDTestURLResponse *tokenResponse = [MSIDTestURLResponse rtResponseForScopes:expectedScopes authority:authority - tenantId:nil + tenantId:@"1234-5678-90abcdefg" + uid:@"1" user:account claims:nil]; @@ -2347,6 +2453,11 @@ - (void)testAcquireTokenSilent_whenFRTUsedAndServerReturnsInvalidGrant_ShouldUse NSError *error = nil; MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] initWithClientId:UNIT_TEST_CLIENT_ID error:&error]; + application.accountMetadataCache = self.accountMetadataCache; + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:authority] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountID.identifier clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; + XCTAssertNotNil(application); XCTestExpectation *expectation = [self expectationWithDescription:@"acquireTokenSilentForScopes"]; @@ -2381,12 +2492,11 @@ - (void)testAcquireTokenSilent_whenNoFRTInCache_ShouldUseMRRTToRefreshAccessToke [json setObject:@"-3600" forKey:MSID_OAUTH2_EXPIRES_IN]; MSIDAADV2TokenResponse *response = [[MSIDAADV2TokenResponse alloc] initWithJSONDictionary:json error:nil]; + MSALAccountId *accountID = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"preferredUserName" - name:@"user@contoso.com" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountID environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; MSIDConfiguration *configuration = [MSIDTestConfiguration v2DefaultConfiguration]; @@ -2405,7 +2515,8 @@ - (void)testAcquireTokenSilent_whenNoFRTInCache_ShouldUseMRRTToRefreshAccessToke // Set up a 200 network responses MSIDTestURLResponse *tokenResponse = [MSIDTestURLResponse rtResponseForScopes:expectedScopes authority:authority - tenantId:nil + tenantId:@"1234-5678-90abcdefg" + uid:@"1" user:account claims:nil]; @@ -2418,6 +2529,12 @@ - (void)testAcquireTokenSilent_whenNoFRTInCache_ShouldUseMRRTToRefreshAccessToke NSError *error = nil; MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] initWithClientId:UNIT_TEST_CLIENT_ID error:&error]; + application.accountMetadataCache = self.accountMetadataCache; + + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:authority] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountID.identifier clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; + XCTAssertNotNil(application); XCTestExpectation *expectation = [self expectationWithDescription:@"acquireTokenSilentForScopes"]; @@ -2490,12 +2607,11 @@ - (void)testAcquireTokenInteractive_whenAccountMismatch_shouldReturnAccountMisma __block MSALResult *result = nil; application.webviewType = MSALWebviewTypeWKWebView; + MSALAccountId *accountID = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"preferredUserName" - name:@"user@contoso.com" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountID environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; [application acquireTokenForScopes:@[@"fakescope"] extraScopesToConsent:nil diff --git a/MSAL/test/unit/MSALB2CPolicyTests.m b/MSAL/test/unit/MSALB2CPolicyTests.m index 874597dfa8..f6d27ac0b2 100644 --- a/MSAL/test/unit/MSALB2CPolicyTests.m +++ b/MSAL/test/unit/MSALB2CPolicyTests.m @@ -40,7 +40,6 @@ #import "MSALAccountId.h" #import "MSIDBaseToken.h" #import "MSIDAADV2Oauth2Factory.h" -#import "MSIDAuthorityFactory.h" #import "MSIDB2CAuthority.h" #import "MSIDAADNetworkConfiguration.h" #import "NSString+MSALTestUtil.h" @@ -150,7 +149,7 @@ - (void)testAcquireToken_whenMultipleB2CPolicies_shouldHaveMultipleUsers XCTAssertNotNil(result); NSString *userIdentifier = [NSString stringWithFormat:@"1-b2c_1_policy.%@", [MSIDTestIdTokenUtil defaultTenantId]]; - XCTAssertEqualObjects(result.account.homeAccountId.identifier, userIdentifier); + XCTAssertEqualObjects(result.account.identifier, userIdentifier); [expectation fulfill]; }]; @@ -177,7 +176,7 @@ - (void)testAcquireToken_whenMultipleB2CPolicies_shouldHaveMultipleUsers XCTAssertNotNil(result); NSString *userIdentifier = [NSString stringWithFormat:@"1-b2c_2_policy.%@", [MSIDTestIdTokenUtil defaultTenantId]]; - XCTAssertEqualObjects(result.account.homeAccountId.identifier, userIdentifier); + XCTAssertEqualObjects(result.account.identifier, userIdentifier); [expectation fulfill]; }]; diff --git a/MSAL/test/unit/MSALErrorConverterTests.m b/MSAL/test/unit/MSALErrorConverterTests.m index 657a5b6d65..ca975ab60f 100644 --- a/MSAL/test/unit/MSALErrorConverterTests.m +++ b/MSAL/test/unit/MSALErrorConverterTests.m @@ -32,11 +32,12 @@ #import "MSIDTestURLResponse+Util.h" #import "MSIDAADV2Oauth2Factory.h" #import "MSIDConfiguration.h" -#import "MSIDAuthorityFactory.h" +#import "NSString+MSIDTestUtil.h" #import "MSIDTokenResponse.h" #import "MSIDAccessToken.h" #import "MSIDRefreshToken.h" #import "MSALResult.h" +#import "MSALAADOauth2Provider.h" @interface MSALErrorConverterTests : XCTestCase @@ -68,7 +69,9 @@ - (void)testErrorConversion_whenPassInNilDomain_ShouldReturnNil { subError:nil underlyingError:nil correlationId:nil - userInfo:nil]; + userInfo:nil + classifyErrors:YES + msalOauth2Provider:nil]; XCTAssertNil(msalError); } @@ -91,7 +94,9 @@ - (void)testErrorConversion_whenOnlyErrorDomainIsMapped_ErrorCodeShouldBeKept { correlationId:correlationId userInfo:@{MSIDHTTPHeadersKey : httpHeaders, MSIDHTTPResponseCodeKey : httpResponseCode, - @"additional_user_info": @"unmapped_userinfo"}]; + @"additional_user_info": @"unmapped_userinfo"} + classifyErrors:YES + msalOauth2Provider:nil]; NSString *expectedErrorDomain = NSOSStatusErrorDomain; XCTAssertNotNil(msalError); @@ -111,6 +116,90 @@ - (void)testErrorConversion_whenOnlyErrorDomainIsMapped_ErrorCodeShouldBeKept { XCTAssertEqualObjects(msalError.userInfo[@"additional_user_info"], @"unmapped_userinfo"); } +- (void)testErrorConversion_whenUnclassifiedInternalMSALErrorPassed_shouldMapToInternal +{ + NSInteger errorCode = -42400; + NSString *errorDescription = @"a fake error description."; + NSString *oauthError = @"a fake oauth error message."; + NSString *subError = @"a fake suberror"; + + NSError *msalError = [MSALErrorConverter errorWithDomain:MSALErrorDomain + code:errorCode + errorDescription:errorDescription + oauthError:oauthError + subError:subError + underlyingError:nil + correlationId:nil + userInfo:nil + classifyErrors:YES + msalOauth2Provider:nil]; + + NSString *expectedErrorDomain = MSALErrorDomain; + XCTAssertNotNil(msalError); + XCTAssertEqualObjects(msalError.domain, expectedErrorDomain); + XCTAssertEqual(msalError.code, MSALErrorInternal); + XCTAssertEqualObjects(msalError.userInfo[MSALErrorDescriptionKey], errorDescription); + XCTAssertEqualObjects(msalError.userInfo[MSALOAuthErrorKey], oauthError); + XCTAssertEqualObjects(msalError.userInfo[MSALOAuthSubErrorKey], subError); + XCTAssertEqualObjects(msalError.userInfo[MSALInternalErrorCodeKey], @(-42400)); +} + +- (void)testErrorConversion_whenUnclassifiedRecoverableErrorPassed_shouldMapToRecoverable +{ + NSInteger errorCode = MSALErrorUserCanceled; + NSString *errorDescription = @"a fake error description."; + NSString *oauthError = @"a fake oauth error message."; + NSString *subError = @"a fake suberror"; + + NSError *msalError = [MSALErrorConverter errorWithDomain:MSALErrorDomain + code:errorCode + errorDescription:errorDescription + oauthError:oauthError + subError:subError + underlyingError:nil + correlationId:nil + userInfo:nil + classifyErrors:YES + msalOauth2Provider:nil]; + + NSString *expectedErrorDomain = MSALErrorDomain; + XCTAssertNotNil(msalError); + XCTAssertEqualObjects(msalError.domain, expectedErrorDomain); + XCTAssertEqual(msalError.code, MSALErrorUserCanceled); + XCTAssertEqualObjects(msalError.userInfo[MSALErrorDescriptionKey], errorDescription); + XCTAssertEqualObjects(msalError.userInfo[MSALOAuthErrorKey], oauthError); + XCTAssertEqualObjects(msalError.userInfo[MSALOAuthSubErrorKey], subError); + XCTAssertNil(msalError.userInfo[MSALInternalErrorCodeKey]); +} + +- (void)testErrorConversion_whenUnclassifiedUnrecoverableErrorPassed_andClassifyErrorsNO_shouldNotClassify +{ + NSInteger errorCode = -42400; + NSString *errorDescription = @"a fake error description."; + NSString *oauthError = @"a fake oauth error message."; + NSString *subError = @"a fake suberror"; + + NSError *msalError = [MSALErrorConverter errorWithDomain:MSALErrorDomain + code:errorCode + errorDescription:errorDescription + oauthError:oauthError + subError:subError + underlyingError:nil + correlationId:nil + userInfo:nil + classifyErrors:NO + msalOauth2Provider:nil]; + + NSString *expectedErrorDomain = MSALErrorDomain; + XCTAssertNotNil(msalError); + XCTAssertEqualObjects(msalError.domain, expectedErrorDomain); + XCTAssertEqual(msalError.code, -42400); + XCTAssertEqualObjects(msalError.userInfo[MSALErrorDescriptionKey], errorDescription); + XCTAssertEqualObjects(msalError.userInfo[MSALOAuthErrorKey], oauthError); + XCTAssertEqualObjects(msalError.userInfo[MSALOAuthSubErrorKey], subError); + XCTAssertNil(msalError.userInfo[MSALInternalErrorCodeKey]); +} + - (void)testErrorConversion_whenBothErrorDomainAndCodeAreMapped_shouldMapBoth { NSInteger errorCode = MSIDErrorInteractionRequired; NSString *errorDescription = @"a fake error description."; @@ -131,7 +220,11 @@ - (void)testErrorConversion_whenBothErrorDomainAndCodeAreMapped_shouldMapBoth { userInfo:@{MSIDHTTPHeadersKey : httpHeaders, MSIDHTTPResponseCodeKey : httpResponseCode, @"additional_user_info": @"unmapped_userinfo", - MSIDInvalidTokenResultKey : [self testTokenResult]}]; + MSIDInvalidTokenResultKey : [self testTokenResult]} + classifyErrors:YES + msalOauth2Provider:[[MSALAADOauth2Provider alloc] initWithClientId:@"someClientId" + tokenCache:nil + accountMetadataCache:nil]]; NSString *expectedErrorDomain = MSALErrorDomain; NSInteger expectedErrorCode = MSALErrorInteractionRequired; @@ -167,7 +260,7 @@ - (MSIDTokenResult *)testTokenResult foci:nil extExpiresIn:nil]; - MSIDAuthority *authority = [MSIDAuthorityFactory authorityFromUrl:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] context:nil error:nil]; + MSIDAuthority *authority = [@"https://login.microsoftonline.com/common" aadAuthority]; MSIDConfiguration *conf = [[MSIDConfiguration alloc] initWithAuthority:authority redirectUri:nil clientId:@"myclient" target:@"test.scope"]; MSIDAADV2Oauth2Factory *factory = [MSIDAADV2Oauth2Factory new]; @@ -180,7 +273,7 @@ - (MSIDTokenResult *)testTokenResult refreshToken:refreshToken idToken:response.idToken account:account - authority:accessToken.authority + authority:authority correlationId:[NSUUID UUID] tokenResponse:response]; @@ -213,7 +306,9 @@ - (void)testErrorConversion_whenErrorConverterInitialized_shouldMapAllMSIDErrors subError:nil underlyingError:nil correlationId:nil - userInfo:nil]; + userInfo:nil + classifyErrors:YES + msalOauth2Provider:nil]; XCTAssertNotEqual(error.code, errorCode); XCTAssertNotEqualObjects(error.domain, domain); @@ -231,7 +326,9 @@ - (void)testErrorConversion_whenDomainIsMappedAndCodeMissing_shouldReturnMSALInt subError:nil underlyingError:nil correlationId:nil - userInfo:nil]; + userInfo:nil + classifyErrors:YES + msalOauth2Provider:nil]; XCTAssertEqualObjects(msalError.domain, MSALErrorDomain); XCTAssertEqual(msalError.code, MSALErrorInternal); @@ -247,11 +344,32 @@ - (void)testErrorConversion_whenDomainNotMapped_shouldNotTouchCode subError:nil underlyingError:nil correlationId:nil - userInfo:nil]; + userInfo:nil + classifyErrors:YES + msalOauth2Provider:nil]; XCTAssertEqualObjects(msalError.domain, @"Unmapped Domain"); XCTAssertEqual(msalError.code, MSIDErrorUserCancel); } +- (void)testErrorConversion_whenErrorMappedToInternalError_shouldSetInternalErrorToUnexpected +{ + NSError *msalError = [MSALErrorConverter errorWithDomain:MSIDErrorDomain + code:MSIDErrorInternal + errorDescription:nil + oauthError:nil + subError:nil + underlyingError:nil + correlationId:nil + userInfo:nil + classifyErrors:YES + msalOauth2Provider:nil]; + + XCTAssertEqualObjects(msalError.domain, MSALErrorDomain); + XCTAssertEqual(msalError.code, MSALErrorInternal); + NSNumber *internalCode = msalError.userInfo[MSALInternalErrorCodeKey]; + XCTAssertEqual([internalCode integerValue], MSALInternalErrorUnexpected); +} + @end diff --git a/MSAL/test/unit/MSALExternalAccountHandlerTests.m b/MSAL/test/unit/MSALExternalAccountHandlerTests.m new file mode 100644 index 0000000000..c7599fa0f7 --- /dev/null +++ b/MSAL/test/unit/MSALExternalAccountHandlerTests.m @@ -0,0 +1,368 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALExternalAccountHandler.h" +#import "MSALOauth2Provider.h" +#import "MSALTestConstants.h" +#import "MSALAccount+Internal.h" +#import "MSALAccountId+Internal.h" +#import + +@interface MSALTestExternalAccountsProvider : NSObject + +@property (nonatomic) BOOL accountOperationResult; +@property (nonatomic) NSError *accountOperationError; +@property (nonatomic) NSArray *resultAccounts; + +@property (nonatomic) NSInteger updateAccountInvokedCount; +@property (nonatomic) NSInteger removeAccountInvokedCount; +@property (nonatomic) NSInteger readAccountsInvokedCount; + +@end + +@implementation MSALTestExternalAccountsProvider + +- (BOOL)updateAccount:(id)account + idTokenClaims:(NSDictionary *)idTokenClaims + error:(NSError * _Nullable * _Nullable)error +{ + self.updateAccountInvokedCount++; + + if (self.accountOperationError && error) + { + *error = self.accountOperationError; + } + + return self.accountOperationResult; +} + +- (BOOL)removeAccount:(id)account + tenantProfiles:(nullable NSArray *)tenantProfiles + error:(NSError * _Nullable * _Nullable)error +{ + self.removeAccountInvokedCount++; + + if (self.accountOperationError && error) + { + *error = self.accountOperationError; + } + + return self.accountOperationResult; +} + +- (nullable NSArray> *)accountsWithParameters:(MSALAccountEnumerationParameters *)parameters + error:(NSError * _Nullable * _Nullable)error +{ + self.readAccountsInvokedCount++; + + if (self.accountOperationError && error) + { + *error = self.accountOperationError; + } + + return self.resultAccounts; +} + +@end + +@interface MSALExternalAccountHandlerTests : XCTestCase + +@end + +@implementation MSALExternalAccountHandlerTests + +#pragma mark - Init + +- (MSALOauth2Provider *)testOauth2Provider +{ + return [[MSALOauth2Provider alloc] initWithClientId:UNIT_TEST_CLIENT_ID tokenCache:nil accountMetadataCache:nil]; +} + +- (void)testInitWithExternalAccountsProvider_whenNilProviders_shouldReturnNilResultAndNilError +{ + NSArray *externalAccountProviders = nil; + NSError *error = nil; + MSALExternalAccountHandler *handler = [[MSALExternalAccountHandler alloc] initWithExternalAccountProviders:externalAccountProviders oauth2Provider:[self testOauth2Provider] error:&error]; + XCTAssertNil(handler); + XCTAssertNil(error); +} + +- (void)testInitWithExternalAccountsProvider_whenEmptyProvidersArray_shouldReturnNilResultAndNilError +{ + NSArray *externalAccountProviders = @[]; + NSError *error = nil; + MSALExternalAccountHandler *handler = [[MSALExternalAccountHandler alloc] initWithExternalAccountProviders:externalAccountProviders oauth2Provider:[self testOauth2Provider] error:&error]; + XCTAssertNil(handler); + XCTAssertNil(error); +} + +- (void)testInitWithExternalAccountsProvider_whenNoOauth2Provider_shouldReturnNilResultAndNonNilError +{ + NSArray *externalAccountProviders = @[[MSALTestExternalAccountsProvider new]]; + MSALOauth2Provider *oauth2Provider = nil; + NSError *error = nil; + MSALExternalAccountHandler *handler = [[MSALExternalAccountHandler alloc] initWithExternalAccountProviders:externalAccountProviders oauth2Provider:oauth2Provider error:&error]; + XCTAssertNil(handler); + XCTAssertNotNil(error); + XCTAssertEqual(error.code, MSALErrorInternal); +} + +- (void)testInitWithExternalAccountsProvider_whenAllParametersProvided_shouldReturnNotNilResultAndNilError +{ + NSArray *externalAccountProviders = @[[MSALTestExternalAccountsProvider new]]; + MSALOauth2Provider *oauth2Provider = [self testOauth2Provider]; + NSError *error = nil; + MSALExternalAccountHandler *handler = [[MSALExternalAccountHandler alloc] initWithExternalAccountProviders:externalAccountProviders oauth2Provider:oauth2Provider error:&error]; + XCTAssertNotNil(handler); + XCTAssertNil(error); +} + +#pragma mark - allExternalAccountsWithParameters + +- (void)testAllExternalAccountsWithParameters_whenFailedToReadExternalAccounts_shouldReturnError +{ + MSALTestExternalAccountsProvider *testProvider = [MSALTestExternalAccountsProvider new]; + NSError *error = MSIDCreateError(MSIDErrorDomain, MSIDErrorInternal, @"Unexpected account reading error", nil, nil, nil, [NSUUID UUID], @{@"extra":@"extra1"}); + testProvider.accountOperationError = error; + + NSArray *externalAccountProviders = @[testProvider]; + MSALOauth2Provider *oauth2Provider = [self testOauth2Provider]; + MSALExternalAccountHandler *handler = [[MSALExternalAccountHandler alloc] initWithExternalAccountProviders:externalAccountProviders + oauth2Provider:oauth2Provider + error:nil]; + + MSALAccountEnumerationParameters *parameters = [MSALAccountEnumerationParameters new]; + NSError *accountsError = nil; + NSArray *results = [handler allExternalAccountsWithParameters:parameters error:&accountsError]; + XCTAssertNil(results); + XCTAssertNotNil(accountsError); + + XCTAssertEqual(accountsError.code, MSALErrorInternal); + XCTAssertEqualObjects(accountsError.userInfo[MSALErrorDescriptionKey], @"Unexpected account reading error"); + XCTAssertEqual(testProvider.readAccountsInvokedCount, 1); +} + +- (void)testAllExternalAccountsWithParameters_whenAccountsFromSameProvider_shouldReturnAll +{ + MSALTestExternalAccountsProvider *testProvider = [MSALTestExternalAccountsProvider new]; + MSALAccountId *homeAccountId1 = [[MSALAccountId alloc] initWithAccountIdentifier:@"id1" objectId:@"oid1" tenantId:@"tid1"]; + MSALAccount *account1 = [[MSALAccount alloc] initWithUsername:@"username" homeAccountId:homeAccountId1 environment:@"contoso.com" tenantProfiles:nil]; + MSALAccountId *homeAccountId2 = [[MSALAccountId alloc] initWithAccountIdentifier:@"id2" objectId:@"oid2" tenantId:@"tid2"]; + MSALAccount *account2 = [[MSALAccount alloc] initWithUsername:@"username2" homeAccountId:homeAccountId2 environment:@"contoso.com2" tenantProfiles:nil]; + testProvider.resultAccounts = @[account1, account2]; + + NSArray *externalAccountProviders = @[testProvider]; + MSALOauth2Provider *oauth2Provider = [self testOauth2Provider]; + MSALExternalAccountHandler *handler = [[MSALExternalAccountHandler alloc] initWithExternalAccountProviders:externalAccountProviders + oauth2Provider:oauth2Provider + error:nil]; + + MSALAccountEnumerationParameters *parameters = [MSALAccountEnumerationParameters new]; + NSError *accountsError = nil; + NSArray *results = [handler allExternalAccountsWithParameters:parameters error:&accountsError]; + XCTAssertNotNil(results); + XCTAssertEqual([results count], 2); + MSALAccount *firstAccount = results[0]; + XCTAssertEqualObjects(firstAccount.username, @"username"); + XCTAssertEqualObjects(firstAccount.environment, @"contoso.com"); + XCTAssertEqualObjects(firstAccount.identifier, @"id1"); + + MSALAccount *secondAccount = results[1]; + XCTAssertEqualObjects(secondAccount.username, @"username2"); + XCTAssertEqualObjects(secondAccount.environment, @"contoso.com2"); + XCTAssertEqualObjects(secondAccount.identifier, @"id2"); + + XCTAssertNil(accountsError); +} + +- (void)testAllExternalAccountsWithParameters_whenAccountsFromMultipleProvider_shouldReturnAll +{ + MSALAccountId *homeAccountId1 = [[MSALAccountId alloc] initWithAccountIdentifier:@"id1" objectId:@"oid1" tenantId:@"tid1"]; + MSALAccount *account1 = [[MSALAccount alloc] initWithUsername:@"username" homeAccountId:homeAccountId1 environment:@"contoso.com" tenantProfiles:nil]; + MSALAccountId *homeAccountId2 = [[MSALAccountId alloc] initWithAccountIdentifier:@"id2" objectId:@"oid2" tenantId:@"tid2"]; + MSALAccount *account2 = [[MSALAccount alloc] initWithUsername:@"username2" homeAccountId:homeAccountId2 environment:@"contoso.com2" tenantProfiles:nil]; + + MSALTestExternalAccountsProvider *testProvider1 = [MSALTestExternalAccountsProvider new]; + testProvider1.resultAccounts = @[account1]; + + MSALTestExternalAccountsProvider *testProvider2 = [MSALTestExternalAccountsProvider new]; + testProvider2.resultAccounts = @[account2]; + + MSALTestExternalAccountsProvider *testProvider3 = [MSALTestExternalAccountsProvider new]; + testProvider3.resultAccounts = nil; + + NSArray *externalAccountProviders = @[testProvider1, testProvider2, testProvider3]; + MSALOauth2Provider *oauth2Provider = [self testOauth2Provider]; + MSALExternalAccountHandler *handler = [[MSALExternalAccountHandler alloc] initWithExternalAccountProviders:externalAccountProviders + oauth2Provider:oauth2Provider + error:nil]; + + MSALAccountEnumerationParameters *parameters = [MSALAccountEnumerationParameters new]; + NSError *accountsError = nil; + NSArray *results = [handler allExternalAccountsWithParameters:parameters error:&accountsError]; + XCTAssertNotNil(results); + XCTAssertEqual([results count], 2); + MSALAccount *firstAccount = results[0]; + XCTAssertEqualObjects(firstAccount.username, @"username"); + XCTAssertEqualObjects(firstAccount.environment, @"contoso.com"); + XCTAssertEqualObjects(firstAccount.identifier, @"id1"); + + MSALAccount *secondAccount = results[1]; + XCTAssertEqualObjects(secondAccount.username, @"username2"); + XCTAssertEqualObjects(secondAccount.environment, @"contoso.com2"); + XCTAssertEqualObjects(secondAccount.identifier, @"id2"); + + XCTAssertNil(accountsError); +} + +#pragma mark - updateWithResult + +- (void)testUpdateWithResult_whenNilResult_shouldReturnNoAndFillError +{ + MSALTestExternalAccountsProvider *testProvider = [MSALTestExternalAccountsProvider new]; + NSArray *externalAccountProviders = @[testProvider]; + MSALOauth2Provider *oauth2Provider = [self testOauth2Provider]; + MSALExternalAccountHandler *handler = [[MSALExternalAccountHandler alloc] initWithExternalAccountProviders:externalAccountProviders + oauth2Provider:oauth2Provider + error:nil]; + + MSALResult *nilResult = nil; + NSError *updateError = nil; + BOOL result = [handler updateWithResult:nilResult error:&updateError]; + XCTAssertFalse(result); + XCTAssertNotNil(updateError); + XCTAssertEqual(updateError.code, MSALErrorInternal); + XCTAssertEqual(testProvider.updateAccountInvokedCount, 0); +} + +- (void)testUpdateWithResult_whenFailedToUpdate_shouldReturnNoAndFillError +{ + MSALTestExternalAccountsProvider *testProvider = [MSALTestExternalAccountsProvider new]; + testProvider.accountOperationResult = NO; + NSError *error = MSIDCreateError(MSIDErrorDomain, MSIDErrorInternal, @"Unexpected update error", nil, nil, nil, [NSUUID UUID], @{@"extra":@"extra1"}); + testProvider.accountOperationError = error; + + NSArray *externalAccountProviders = @[testProvider]; + MSALOauth2Provider *oauth2Provider = [self testOauth2Provider]; + MSALExternalAccountHandler *handler = [[MSALExternalAccountHandler alloc] initWithExternalAccountProviders:externalAccountProviders + oauth2Provider:oauth2Provider + error:nil]; + + MSALResult *result = [MSALResult new]; + NSError *updateError = nil; + BOOL updateResult = [handler updateWithResult:result error:&updateError]; + XCTAssertFalse(updateResult); + XCTAssertNotNil(updateError); + + XCTAssertEqual(updateError.code, MSALErrorInternal); + XCTAssertEqualObjects(updateError.userInfo[MSALErrorDescriptionKey], @"Unexpected update error"); + XCTAssertEqual(testProvider.updateAccountInvokedCount, 1); +} + +- (void)testUpdateWithResult_whenUpdateSucceeded_shouldReturnYesAndNilError +{ + MSALTestExternalAccountsProvider *testProvider = [MSALTestExternalAccountsProvider new]; + testProvider.accountOperationResult = YES; + + NSArray *externalAccountProviders = @[testProvider]; + MSALOauth2Provider *oauth2Provider = [self testOauth2Provider]; + MSALExternalAccountHandler *handler = [[MSALExternalAccountHandler alloc] initWithExternalAccountProviders:externalAccountProviders + oauth2Provider:oauth2Provider + error:nil]; + + MSALResult *result = [MSALResult new]; + NSError *updateError = nil; + BOOL updateResult = [handler updateWithResult:result error:&updateError]; + XCTAssertTrue(updateResult); + XCTAssertNil(updateError); + XCTAssertEqual(testProvider.updateAccountInvokedCount, 1); +} + +#pragma mark - removeAccount + +- (void)testRemoveAccount_whenNilAccount_shouldReturnNoAndFillError +{ + MSALTestExternalAccountsProvider *testProvider = [MSALTestExternalAccountsProvider new]; + NSArray *externalAccountProviders = @[testProvider]; + MSALOauth2Provider *oauth2Provider = [self testOauth2Provider]; + MSALExternalAccountHandler *handler = [[MSALExternalAccountHandler alloc] initWithExternalAccountProviders:externalAccountProviders + oauth2Provider:oauth2Provider + error:nil]; + + MSALAccount *nilAccount = nil; + NSError *removeError = nil; + BOOL result = [handler removeAccount:nilAccount error:&removeError]; + XCTAssertFalse(result); + XCTAssertNotNil(removeError); + XCTAssertEqual(removeError.code, MSALErrorInternal); + XCTAssertEqual(testProvider.removeAccountInvokedCount, 0); +} + +- (void)testRemoveAccount_whenFailedToRemove_shouldReturnNoAndFillError +{ + MSALTestExternalAccountsProvider *testProvider = [MSALTestExternalAccountsProvider new]; + testProvider.accountOperationResult = NO; + NSError *error = MSIDCreateError(MSIDErrorDomain, MSIDErrorInternal, @"Unexpected removal error", nil, nil, nil, [NSUUID UUID], @{@"extra":@"extra1"}); + testProvider.accountOperationError = error; + + NSArray *externalAccountProviders = @[testProvider]; + MSALOauth2Provider *oauth2Provider = [self testOauth2Provider]; + MSALExternalAccountHandler *handler = [[MSALExternalAccountHandler alloc] initWithExternalAccountProviders:externalAccountProviders + oauth2Provider:oauth2Provider + error:nil]; + + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"username" homeAccountId:nil environment:@"login.microsoftonline.com" tenantProfiles:nil]; + NSError *removeError = nil; + BOOL result = [handler removeAccount:account error:&removeError]; + XCTAssertFalse(result); + XCTAssertNotNil(removeError); + XCTAssertEqual(removeError.code, MSALErrorInternal); + XCTAssertEqualObjects(removeError.userInfo[MSALErrorDescriptionKey], @"Unexpected removal error"); + XCTAssertEqual(testProvider.removeAccountInvokedCount, 1); +} + +- (void)testRemoveAccount_whenRemovalSucceeded_shouldReturnYesAndNilError +{ + MSALTestExternalAccountsProvider *testProvider = [MSALTestExternalAccountsProvider new]; + testProvider.accountOperationResult = YES; + + NSArray *externalAccountProviders = @[testProvider]; + MSALOauth2Provider *oauth2Provider = [self testOauth2Provider]; + MSALExternalAccountHandler *handler = [[MSALExternalAccountHandler alloc] initWithExternalAccountProviders:externalAccountProviders + oauth2Provider:oauth2Provider + error:nil]; + + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"username" homeAccountId:nil environment:@"login.microsoftonline.com" tenantProfiles:nil]; + NSError *removeError = nil; + BOOL result = [handler removeAccount:account error:&removeError]; + XCTAssertTrue(result); + XCTAssertNil(removeError); + XCTAssertEqual(testProvider.removeAccountInvokedCount, 1); +} + +@end diff --git a/MSAL/test/unit/MSALOauth2FactoryProducerTests.m b/MSAL/test/unit/MSALOauth2FactoryProducerTests.m index 7e47e4d384..c1cafccffa 100644 --- a/MSAL/test/unit/MSALOauth2FactoryProducerTests.m +++ b/MSAL/test/unit/MSALOauth2FactoryProducerTests.m @@ -26,10 +26,14 @@ //------------------------------------------------------------------------------ #import -#import "MSALOauth2FactoryProducer.h" +#import "MSALOauth2ProviderFactory.h" #import "MSIDOauth2Factory.h" -#import "MSIDAADV2Oauth2Factory.h" -#import "MSIDB2COauth2Factory.h" +#import "MSALAADOauth2Provider.h" +#import "MSALB2COauth2Provider.h" +#import "MSALAADAuthority.h" +#import "MSALB2CAuthority.h" +#import "MSALADFSOauth2Provider.h" +#import "MSALADFSAuthority.h" @interface MSALOauth2FactoryProducerTests : XCTestCase @@ -40,10 +44,11 @@ @implementation MSALOauth2FactoryProducerTests - (void)testOauth2FactoryForAuthority_whenNilAuthority_shouldReturnNilAndError { NSError *error = nil; - NSURL *authorityURL = nil; - MSIDOauth2Factory *factory = [MSALOauth2FactoryProducer msidOauth2FactoryForAuthority:authorityURL context:nil error:&error]; + MSALAuthority *authority = nil; + + MSALOauth2Provider *provider = [MSALOauth2ProviderFactory oauthProviderForAuthority:authority clientId:@"someClientId" tokenCache:nil accountMetadataCache:nil context:nil error:&error]; - XCTAssertNil(factory); + XCTAssertNil(provider); XCTAssertNotNil(error); } @@ -51,33 +56,43 @@ - (void)testOauth2FactoryForAuthority_whenB2CAuthority_shouldReturnB2CFactoryNil { NSError *error = nil; NSURL *authorityURL = [NSURL URLWithString:@"https://login.microsoftonline.com/tfp/contoso.com/B2C_1_Signin"]; - MSIDOauth2Factory *factory = [MSALOauth2FactoryProducer msidOauth2FactoryForAuthority:authorityURL context:nil error:&error]; + MSALB2CAuthority *authorityObj = [[MSALB2CAuthority alloc] initWithURL:authorityURL error:nil]; + MSALOauth2Provider *factory = [MSALOauth2ProviderFactory oauthProviderForAuthority:authorityObj clientId:@"someClientId" tokenCache:nil accountMetadataCache:nil context:nil error:&error]; XCTAssertNotNil(factory); XCTAssertNil(error); - XCTAssertTrue([factory isKindOfClass:[MSIDB2COauth2Factory class]]); + XCTAssertTrue([factory isKindOfClass:[MSALB2COauth2Provider class]]); } - (void)testOauth2FactoryForAuthority_whenAADAuthority_shouldReturnAADV2FactoryNilError { NSError *error = nil; NSURL *authorityURL = [NSURL URLWithString:@"https://login.microsoftonline.com/contoso.com/"]; - MSIDOauth2Factory *factory = [MSALOauth2FactoryProducer msidOauth2FactoryForAuthority:authorityURL context:nil error:&error]; + MSALAADAuthority *authorityObj = [[MSALAADAuthority alloc] initWithURL:authorityURL error:nil]; + MSALOauth2Provider *factory = [MSALOauth2ProviderFactory oauthProviderForAuthority:authorityObj clientId:@"someClientId" tokenCache:nil accountMetadataCache:nil context:nil error:&error]; XCTAssertNotNil(factory); XCTAssertNil(error); - XCTAssertTrue([factory isKindOfClass:[MSIDAADV2Oauth2Factory class]]); + XCTAssertTrue([factory isKindOfClass:[MSALAADOauth2Provider class]]); } +#ifndef ADFS_NOT_YET_SUPPORTED +#define ADFS_NOT_YET_SUPPORTED +#endif + +#ifndef ADFS_NOT_YET_SUPPORTED - (void)testOauth2FactoryForAuthority_whenADFSAuthority_shouldReturnAADV2FactoryNilError { NSError *error = nil; NSURL *authorityURL = [NSURL URLWithString:@"https://contoso.com/adfs"]; - MSIDOauth2Factory *factory = [MSALOauth2FactoryProducer msidOauth2FactoryForAuthority:authorityURL context:nil error:&error]; - + + MSALADFSAuthority *authorityObj = [[MSALADFSAuthority alloc] initWithURL:authorityURL error:nil]; + MSALOauth2Provider *factory = [MSALOauth2ProviderFactory oauthProviderForAuthority:authorityObj context:nil error:&error]; + XCTAssertNotNil(factory); XCTAssertNil(error); - XCTAssertTrue([factory isKindOfClass:[MSIDAADV2Oauth2Factory class]]); + XCTAssertTrue([factory isKindOfClass:[MSALADFSOauth2Provider class]]); } +#endif @end diff --git a/MSAL/test/unit/MSALPublicClientApplicationAccountUpdateTests.m b/MSAL/test/unit/MSALPublicClientApplicationAccountUpdateTests.m new file mode 100644 index 0000000000..0431e65a25 --- /dev/null +++ b/MSAL/test/unit/MSALPublicClientApplicationAccountUpdateTests.m @@ -0,0 +1,170 @@ +//------------------------------------------------------------------------------ +// +// 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 "NSString+MSALTestUtil.h" +#import "MSALTestConstants.h" +#import +#import "MSIDTestSwizzle.h" +#import "MSIDTokenResult.h" +#import "MSIDLocalInteractiveController.h" +#import "MSIDAccount.h" +#import "MSIDAccountIdentifier.h" +#import "MSALMockExternalAccountHandler.h" +#import "MSIDAccessToken.h" +#import "MSIDAADAuthority.h" +#import "MSIDSilentController.h" +#import "MSIDTestIdTokenUtil.h" +#import "MSALAccountId+Internal.h" +#import "MSALAccount+Internal.h" +#import "MSIDDefaultTokenCacheAccessor.h" +#import "MSALTestBundle.h" +#import "MSALOauth2Provider.h" + +@interface MSALPublicClientApplicationAccountUpdateTests : XCTestCase + +@end + +@implementation MSALPublicClientApplicationAccountUpdateTests + +#pragma mark - Setup + +- (void)setUp +{ + [super setUp]; + NSArray *override = @[ @{ @"CFBundleURLSchemes" : @[UNIT_TEST_DEFAULT_REDIRECT_SCHEME] } ]; + [MSALTestBundle overrideObject:override forKey:@"CFBundleURLTypes"]; +} + +#pragma mark - Tests + +- (void)testAcquireToken_whenSuccessfulResponse_shouldUpdateExternalAccount +{ + NSError *error = nil; + MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] initWithClientId:UNIT_TEST_CLIENT_ID error:&error]; + MSALMockExternalAccountHandler *mockExternalAccountHandler = [MSALMockExternalAccountHandler new]; + application.externalAccountHandler = mockExternalAccountHandler; + + XCTAssertNotNil(application); + XCTAssertNil(error); + + [MSIDTestSwizzle instanceMethod:@selector(acquireToken:) + class:[MSIDLocalInteractiveController class] + block:(id)^(MSIDLocalInteractiveController *obj, MSIDRequestCompletionBlock completionBlock) + { + XCTAssertTrue([obj isKindOfClass:[MSIDLocalInteractiveController class]]); + completionBlock([self testTokenResult], nil); + }]; + +#if TARGET_OS_IPHONE + MSALGlobalConfig.brokerAvailability = MSALBrokeredAvailabilityNone; +#endif + + [application acquireTokenForScopes:@[@"fakescope1", @"fakescope2"] + loginHint:@"fakeuser@contoso.com" + completionBlock:^(MSALResult *result, NSError *error) + { + XCTAssertNotNil(result); + XCTAssertNil(error); + XCTAssertEqual(mockExternalAccountHandler.updateInvokedCount, 1); + }]; +} + +- (void)testAcquireTokenSilent_whenSuccessfulResponse_shouldUpdateExternalAccount +{ + NSError *error = nil; + MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] initWithClientId:UNIT_TEST_CLIENT_ID error:&error]; + MSALMockExternalAccountHandler *mockExternalAccountHandler = [MSALMockExternalAccountHandler new]; + application.externalAccountHandler = mockExternalAccountHandler; + + XCTAssertNotNil(application); + XCTAssertNil(error); + + [MSIDTestSwizzle instanceMethod:@selector(acquireToken:) + class:[MSIDSilentController class] + block:(id)^(MSIDSilentController *obj, MSIDRequestCompletionBlock completionBlock) + { + XCTAssertTrue([obj isKindOfClass:[MSIDSilentController class]]); + + completionBlock([self testTokenResult], nil); + }]; + + [application acquireTokenSilentForScopes:@[@"fakescope1", @"fakescope2"] + account:[self testMSALAccount] + completionBlock:^(MSALResult * _Nullable result, NSError * _Nullable error) { + + XCTAssertNotNil(result); + XCTAssertNil(error); + XCTAssertEqual(mockExternalAccountHandler.updateInvokedCount, 1); + }]; +} + +- (void)testRemoveAccount_whenAccountExistsInExternalCache_shouldCallRemoveAccountFromExternalCache +{ + NSError *error = nil; + MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] initWithClientId:UNIT_TEST_CLIENT_ID error:&error]; + MSALMockExternalAccountHandler *mockExternalAccountHandler = [MSALMockExternalAccountHandler new]; + mockExternalAccountHandler.accountOperationResult = YES; + application.externalAccountHandler = mockExternalAccountHandler; + application.msalOauth2Provider = [[MSALOauth2Provider alloc] initWithClientId:UNIT_TEST_CLIENT_ID tokenCache:nil accountMetadataCache:nil]; + + XCTAssertNotNil(application); + XCTAssertNil(error); + + NSError *removalError = nil; + BOOL result = [application removeAccount:[self testMSALAccount] error:&removalError]; + XCTAssertTrue(result); + XCTAssertNil(removalError); + XCTAssertEqual(mockExternalAccountHandler.removeAccountCount, 1); +} + +#pragma mark - Helpers + +- (MSIDTokenResult *)testTokenResult +{ + MSIDTokenResult *tokenResult = [MSIDTokenResult new]; + MSIDAccount *account = [MSIDAccount new]; + account.accountIdentifier = [[MSIDAccountIdentifier alloc] initWithDisplayableId:@"fakeuser@contoso.com" homeAccountId:@"uid.utid"]; + account.username = @"fakeuser@contoso.com"; + account.environment = @"login.microsoftonline.com"; + account.realm = @"contoso.com"; + tokenResult.account = account; + tokenResult.accessToken = [MSIDAccessToken new]; + tokenResult.accessToken.accessToken = @"access.token"; + tokenResult.authority = [[MSIDAADAuthority alloc] initWithURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] rawTenant:@"tenant" context:nil error:nil]; + tokenResult.rawIdToken = [MSIDTestIdTokenUtil defaultV2IdToken]; + return tokenResult; +} + +- (MSALAccount *)testMSALAccount +{ + MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"uid.utid" objectId:@"uid" tenantId:@"utid"]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:nil homeAccountId:accountId environment:@"login.microsoftonline.com" tenantProfiles:nil]; + return account; +} + +@end diff --git a/MSAL/test/unit/MSALPublicClientApplicationTests.m b/MSAL/test/unit/MSALPublicClientApplicationTests.m index 27785714c9..6f4d0d89c6 100644 --- a/MSAL/test/unit/MSALPublicClientApplicationTests.m +++ b/MSAL/test/unit/MSALPublicClientApplicationTests.m @@ -50,11 +50,10 @@ #import "MSALAADAuthority.h" #import "MSALAuthority_Internal.h" #import "MSIDMacTokenCache.h" -#import "MSIDAuthorityFactory.h" #import "MSIDTestURLResponse.h" #import "MSIDTestURLSession.h" #import "MSIDDeviceId.h" -#import "MSIDAuthorityFactory.h" +#import "NSString+MSIDTestUtil.h" #import "MSIDAADNetworkConfiguration.h" #import "NSString+MSIDTestUtil.h" #import "MSIDLocalInteractiveController.h" @@ -64,10 +63,19 @@ #import "MSALRedirectUri.h" #import "MSIDAppMetadataCacheItem.h" #import "MSIDTestURLResponse+Util.h" +#import "MSALTenantProfile.h" #import "MSALSliceConfig.h" #import "MSALCacheConfig.h" #import "MSALB2CAuthority.h" #import "MSALAccountId+Internal.h" +#import "MSALCacheConfig.h" +#import "MSALAccount+MultiTenantAccount.h" +#import "MSALAccountEnumerationParameters.h" +#import "MSALAccount+Internal.h" +#import "MSIDLegacyTokenCacheAccessor.h" +#import "MSIDAccountMetadataCacheAccessor.h" +#import "MSIDTestCacheDataSource.h" +#import "MSALOauth2ProviderFactory.h" @interface MSALFakeInteractiveRequest : NSObject @@ -84,6 +92,7 @@ @interface MSALPublicClientApplicationTests : MSALTestCase @property (nonatomic) MSIDClientInfo *clientInfo; @property (nonatomic) MSIDDefaultTokenCacheAccessor *tokenCacheAccessor; +@property (nonatomic) MSIDAccountMetadataCacheAccessor *accountMetadataCache; @end @@ -95,20 +104,18 @@ - (void)setUp NSString *base64String = [@{ @"uid" : @"1", @"utid" : @"1234-5678-90abcdefg"} msidBase64UrlJson]; self.clientInfo = [[MSIDClientInfo alloc] initWithRawClientInfo:base64String error:nil]; - - id dataSource = nil; - #if TARGET_OS_IPHONE - dataSource = MSIDKeychainTokenCache.defaultKeychainCache; + id dataSource = MSIDKeychainTokenCache.defaultKeychainCache; + self.tokenCacheAccessor = [[MSIDDefaultTokenCacheAccessor alloc] initWithDataSource:dataSource otherCacheAccessors:nil]; + self.accountMetadataCache = [[MSIDAccountMetadataCacheAccessor alloc] initWithDataSource:dataSource]; #else - dataSource = MSIDMacTokenCache.defaultCache; + self.tokenCacheAccessor = [[MSIDDefaultTokenCacheAccessor alloc] initWithDataSource:[MSIDTestCacheDataSource new] otherCacheAccessors:nil]; + self.accountMetadataCache = [[MSIDAccountMetadataCacheAccessor alloc] initWithDataSource:[MSIDTestCacheDataSource new]]; #endif - self.tokenCacheAccessor = [[MSIDDefaultTokenCacheAccessor alloc] initWithDataSource:dataSource otherCacheAccessors:nil]; - [self.tokenCacheAccessor clearWithContext:nil error:nil]; - NSArray *override = @[ @{ @"CFBundleURLSchemes" : @[UNIT_TEST_DEFAULT_REDIRECT_SCHEME] } ]; [MSALTestBundle overrideObject:override forKey:@"CFBundleURLTypes"]; + [self.tokenCacheAccessor clearWithContext:nil error:nil]; } - (void)tearDown @@ -121,7 +128,7 @@ - (void)tearDown - (void)testInitWithClientId_whenClientIdIsNil_shouldReturnError { NSError *error = nil; - + NSString *clientId = nil; __auto_type application = [[MSALPublicClientApplication alloc] initWithClientId:clientId @@ -294,7 +301,7 @@ - (void)testInitWithClientId_whenKeychainGroupNotSpecified_shouldHaveDefaultKeyc { NSArray *override = @[ @{ @"CFBundleURLSchemes" : @[UNIT_TEST_DEFAULT_REDIRECT_SCHEME] } ]; [MSALTestBundle overrideObject:override forKey:@"CFBundleURLTypes"]; - + MSALPublicClientApplication *app = [[MSALPublicClientApplication alloc] initWithClientId:UNIT_TEST_CLIENT_ID error:nil]; XCTAssertEqualObjects(app.keychainGroup, MSIDKeychainTokenCache.defaultKeychainGroup); } @@ -303,7 +310,7 @@ - (void)testInitWithClientIdAndAuthority_whenKeychainGroupNotSpecified_shouldHav { NSArray *override = @[ @{ @"CFBundleURLSchemes" : @[UNIT_TEST_DEFAULT_REDIRECT_SCHEME] } ]; [MSALTestBundle overrideObject:override forKey:@"CFBundleURLTypes"]; - + MSALAuthority *authority = [@"https://login.microsoftonline.com/contoso.com" msalAuthority]; MSALPublicClientApplication *app = [[MSALPublicClientApplication alloc] initWithClientId:UNIT_TEST_CLIENT_ID authority:authority error:nil]; XCTAssertEqualObjects(app.keychainGroup, MSIDKeychainTokenCache.defaultKeychainGroup); @@ -313,19 +320,17 @@ - (void)testInitWithClientIdAndAuthorityAndRedirectUri_whenKeychainGroupNotSpeci { NSArray *override = @[ @{ @"CFBundleURLSchemes" : @[@"mycustom.redirect"] } ]; [MSALTestBundle overrideObject:override forKey:@"CFBundleURLTypes"]; - + MSALAuthority *authority = [@"https://login.microsoftonline.com/contoso.com" msalAuthority]; MSALPublicClientApplication *app = [[MSALPublicClientApplication alloc] initWithClientId:UNIT_TEST_CLIENT_ID authority:authority redirectUri:@"mycustom.redirect://bundle_id" error:nil]; XCTAssertEqualObjects(app.keychainGroup, MSIDKeychainTokenCache.defaultKeychainGroup); } - - -- (void)testInitWithClientIdAndAuthorityAndRedirectUriAndKeychainGroup_whenKeychainGroupSpecifiedNil_shouldHaveKeychainGroupWithBundleId +- (void)testInitWithClientIdAndAuthorityAndRedirectUriAndKeychainGroup_whenKeychainGroupSpecifiedNil_shouldHaveKeychainSharingDisabled { NSArray *override = @[ @{ @"CFBundleURLSchemes" : @[@"mycustom.redirect"] } ]; [MSALTestBundle overrideObject:override forKey:@"CFBundleURLTypes"]; - + MSALAuthority *authority = [@"https://login.microsoftonline.com/contoso.com" msalAuthority]; MSALPublicClientApplication *application = @@ -335,14 +340,14 @@ - (void)testInitWithClientIdAndAuthorityAndRedirectUriAndKeychainGroup_whenKeych redirectUri:@"mycustom.redirect://bundle_id" error:nil]; - XCTAssertEqualObjects(application.keychainGroup, [[NSBundle mainBundle] bundleIdentifier]); + XCTAssertEqualObjects(application.keychainGroup, nil); } - (void)testInitWithClientIdAndAuthorityAndRedirectUriAndKeychainGroup_whenKeychainGroupCustomSpecified_shouldHaveCustomKeychainGroup { NSArray *override = @[ @{ @"CFBundleURLSchemes" : @[@"mycustom.redirect"] } ]; [MSALTestBundle overrideObject:override forKey:@"CFBundleURLTypes"]; - + MSALAuthority *authority = [@"https://login.microsoftonline.com/contoso.com" msalAuthority]; MSALPublicClientApplication *application = @@ -380,7 +385,7 @@ - (void)testAcquireTokenScopes XCTAssertTrue([obj isKindOfClass:[MSIDLocalInteractiveController class]]); MSIDInteractiveRequestParameters *params = [obj interactiveRequestParamaters]; XCTAssertNotNil(params); - + NSString *expectedTelemetryAPIId = [NSString stringWithFormat:@"%ld", (long)MSALTelemetryApiIdAcquire]; XCTAssertEqualObjects(params.telemetryApiId, expectedTelemetryAPIId); XCTAssertEqualObjects(params.authority, [@"https://login.microsoftonline.com/common" msalAuthority].msidAuthority); @@ -522,22 +527,20 @@ - (void)testAcquireTokenSilent_whenKnownB2CAuthority_shouldNotValidate XCTAssertNotNil(params); XCTAssertFalse(params.validateAuthority); - XCTAssertEqualObjects(params.authority.url.absoluteString, @"https://contoso.b2clogin.com/tfp/utid/B2C_1_signup-signin"); + XCTAssertEqualObjects(params.authority.url.absoluteString, @"https://contoso.b2clogin.com/tfp/contoso.onmicrosoft.com/B2C_1_signup-signin"); completionBlock(nil, nil); }]; - MSALAccount *account = [MSALAccount new]; MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"uid.utid" objectId:@"uid" tenantId:@"utid"]; - [account setValue:accountId forKey:@"homeAccountId"]; - [account setValue:@"myb2c.authority.com" forKey:@"environment"]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:nil homeAccountId:accountId environment:@"myb2c.authority.com" tenantProfiles:nil]; [application acquireTokenSilentForScopes:@[@"fakescope1", @"fakescope2"] account:account completionBlock:^(MSALResult * _Nullable result, NSError * _Nullable error) { - + XCTAssertNil(result); XCTAssertNotNil(error); - }]; + }]; } - (void)testAcquireTokenSilent_whenNoTfpAuthority_shouldNotValidate @@ -572,10 +575,8 @@ - (void)testAcquireTokenSilent_whenNoTfpAuthority_shouldNotValidate completionBlock(nil, nil); }]; - MSALAccount *account = [MSALAccount new]; MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"uid.utid" objectId:@"uid" tenantId:@"utid"]; - [account setValue:accountId forKey:@"homeAccountId"]; - [account setValue:@"myb2c.authority.com" forKey:@"environment"]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:nil homeAccountId:accountId environment:@"myb2c.authority.com" tenantProfiles:nil]; [application acquireTokenSilentForScopes:@[@"fakescope1", @"fakescope2"] account:account @@ -610,10 +611,10 @@ - (void)testAcquireScopesLoginHint block:(id)^(MSIDLocalInteractiveController *obj, MSIDRequestCompletionBlock completionBlock) { XCTAssertTrue([obj isKindOfClass:[MSIDLocalInteractiveController class]]); - + MSIDInteractiveRequestParameters *params = [obj interactiveRequestParamaters]; XCTAssertNotNil(params); - + NSString *expectedApiId = [NSString stringWithFormat:@"%ld", (long)MSALTelemetryApiIdAcquireWithHint]; XCTAssertEqualObjects(params.telemetryApiId, expectedApiId); XCTAssertEqualObjects(params.authority.url.absoluteString, @"https://login.microsoftonline.com/common"); @@ -630,7 +631,7 @@ - (void)testAcquireScopesLoginHint completionBlock(nil, nil); }]; - + #if TARGET_OS_IPHONE MSALGlobalConfig.brokerAvailability = MSALBrokeredAvailabilityNone; #endif @@ -665,10 +666,10 @@ - (void)testAcquireScopesLoginHintBehaviorEQPs block:(id)^(MSIDLocalInteractiveController *obj, MSIDRequestCompletionBlock completionBlock) { XCTAssertTrue([obj isKindOfClass:[MSIDLocalInteractiveController class]]); - + MSIDInteractiveRequestParameters *params = [obj interactiveRequestParamaters]; XCTAssertNotNil(params); - + NSString *expectedApiId = [NSString stringWithFormat:@"%ld", (long)MSALTelemetryApiIdAcquireWithHintPromptTypeAndParameters]; XCTAssertEqualObjects(params.telemetryApiId, expectedApiId); XCTAssertEqualObjects(params.authority.url.absoluteString, @"https://login.microsoftonline.com/common"); @@ -685,7 +686,7 @@ - (void)testAcquireScopesLoginHintBehaviorEQPs completionBlock(nil, nil); }]; - + #if TARGET_OS_IPHONE MSALGlobalConfig.brokerAvailability = MSALBrokeredAvailabilityNone; #endif @@ -703,7 +704,7 @@ - (void)testAcquireScopesLoginHintBehaviorEQPs - (void)testAcquireScopesAddlScopesLoginHintuiBehaviorEQPAuthorityCorrelationId { - [MSALTestBundle overrideBundleId:@"com.microsoft.unittests"]; + [MSALTestBundle overrideBundleId:@"com.microsoft.unit-test-host"]; __auto_type authority = [@"https://login.microsoftonline.com/common" msalAuthority]; MSALPublicClientApplicationConfig *config = [[MSALPublicClientApplicationConfig alloc] initWithClientId:UNIT_TEST_CLIENT_ID redirectUri:nil @@ -724,10 +725,10 @@ - (void)testAcquireScopesAddlScopesLoginHintuiBehaviorEQPAuthorityCorrelationId block:(id)^(MSIDLocalInteractiveController *obj, MSIDRequestCompletionBlock completionBlock) { XCTAssertTrue([obj isKindOfClass:[MSIDLocalInteractiveController class]]); - + MSIDInteractiveRequestParameters *params = [obj interactiveRequestParamaters]; XCTAssertNotNil(params); - + NSString *expectedApiId = [NSString stringWithFormat:@"%ld", (long)MSALTelemetryApiIdAcquireWithHintPromptTypeParametersAuthorityAndCorrelationId]; XCTAssertEqualObjects(params.telemetryApiId, expectedApiId); XCTAssertEqualObjects(params.authority.url.absoluteString, @"https://login.microsoftonline.com/contoso.com"); @@ -782,22 +783,22 @@ - (void)testAcquireScopesWithAccount XCTAssertNotNil(application); XCTAssertNil(error); + MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:nil tenantId:nil]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"user@contoso.com" - name:@"name" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountId environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; [MSIDTestSwizzle instanceMethod:@selector(acquireToken:) class:[MSIDLocalInteractiveController class] block:(id)^(MSIDLocalInteractiveController *obj, MSIDRequestCompletionBlock completionBlock) { XCTAssertTrue([obj isKindOfClass:[MSIDLocalInteractiveController class]]); - + MSIDInteractiveRequestParameters *params = [obj interactiveRequestParamaters]; XCTAssertNotNil(params); - + NSString *expectedApiId = [NSString stringWithFormat:@"%ld", (long)MSALTelemetryApiIdAcquireWithUserPromptTypeAndParameters]; XCTAssertEqualObjects(params.telemetryApiId, expectedApiId); XCTAssertEqualObjects(params.authority.url.absoluteString, @"https://login.microsoftonline.com/common"); @@ -811,12 +812,12 @@ - (void)testAcquireScopesWithAccount XCTAssertNil(params.loginHint); XCTAssertNil(params.extraScopesToConsent); XCTAssertEqual(params.promptType, MSIDPromptTypePromptIfNecessary); - + XCTAssertEqualObjects(params.accountIdentifier, account.lookupAccountIdentifier); completionBlock(nil, nil); }]; - + #if TARGET_OS_IPHONE MSALGlobalConfig.brokerAvailability = MSALBrokeredAvailabilityNone; #endif @@ -845,22 +846,22 @@ - (void)testAcquireScopesUserUiBehaviorEQP XCTAssertNotNil(application); XCTAssertNil(error); + MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:nil tenantId:nil]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"user@contoso.com" - name:@"name" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountId environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; [MSIDTestSwizzle instanceMethod:@selector(acquireToken:) class:[MSIDLocalInteractiveController class] block:(id)^(MSIDLocalInteractiveController *obj, MSIDRequestCompletionBlock completionBlock) { XCTAssertTrue([obj isKindOfClass:[MSIDLocalInteractiveController class]]); - + MSIDInteractiveRequestParameters *params = [obj interactiveRequestParamaters]; XCTAssertNotNil(params); - + NSString *expectedApiId = [NSString stringWithFormat:@"%ld", (long)MSALTelemetryApiIdAcquireWithUserPromptTypeAndParameters]; XCTAssertEqualObjects(params.telemetryApiId, expectedApiId); XCTAssertEqualObjects(params.authority.url.absoluteString, @"https://login.microsoftonline.com/common"); @@ -878,7 +879,7 @@ - (void)testAcquireScopesUserUiBehaviorEQP completionBlock(nil, nil); }]; - + #if TARGET_OS_IPHONE MSALGlobalConfig.brokerAvailability = MSALBrokeredAvailabilityNone; #endif @@ -912,22 +913,22 @@ - (void)testAcquireScopesAddlScopesUserUiBehaviorEQPAuthorityCorrelationId __block NSUUID *correlationId = [NSUUID new]; + MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:nil tenantId:nil]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"user@contoso.com" - name:@"name" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountId environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; [MSIDTestSwizzle instanceMethod:@selector(acquireToken:) class:[MSIDLocalInteractiveController class] block:(id)^(MSIDLocalInteractiveController *obj, MSIDRequestCompletionBlock completionBlock) { XCTAssertTrue([obj isKindOfClass:[MSIDLocalInteractiveController class]]); - + MSIDInteractiveRequestParameters *params = [obj interactiveRequestParamaters]; XCTAssertNotNil(params); - + NSString *expectedApiId = [NSString stringWithFormat:@"%ld", (long)MSALTelemetryApiIdAcquireWithUserPromptTypeParametersAuthorityAndCorrelationId]; XCTAssertEqualObjects(params.telemetryApiId, expectedApiId); XCTAssertEqualObjects(params.authority.url.absoluteString, @"https://login.microsoftonline.com/contoso.com"); @@ -993,7 +994,7 @@ - (void)testAcquireSilentScopesUser MSIDRequestParameters *params = [obj requestParameters]; XCTAssertNotNil(params); - + NSString *expectedApiId = [NSString stringWithFormat:@"%ld", (long)MSALTelemetryApiIdAcquireSilentWithUser]; XCTAssertEqualObjects(params.telemetryApiId, expectedApiId); XCTAssertEqualObjects(params.accountIdentifier.displayableId, @"user@contoso.com"); @@ -1013,12 +1014,27 @@ - (void)testAcquireSilentScopesUser completionBlock(nil, nil); }]; + MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"user@contoso.com" - name:@"name" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountId environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; + + application.accountMetadataCache = self.accountMetadataCache; + application.msalOauth2Provider = [MSALOauth2ProviderFactory oauthProviderForAuthority:authority + clientId:UNIT_TEST_CLIENT_ID + tokenCache:self.tokenCacheAccessor + accountMetadataCache:self.accountMetadataCache + context:nil + error:nil]; + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:@"https://login.microsoftonline.com/1234-5678-90abcdefg"] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountId.identifier + clientId:UNIT_TEST_CLIENT_ID + instanceAware:NO + context:nil + error:nil]; [application acquireTokenSilentForScopes:@[@"fakescope1", @"fakescope2"] account:account @@ -1050,17 +1066,17 @@ - (void)testAcquireSilentScopesUserAuthority block:(id)^(MSIDSilentController *obj, MSIDRequestCompletionBlock completionBlock) { XCTAssertTrue([obj isKindOfClass:[MSIDSilentController class]]); - + MSIDRequestParameters *params = [obj requestParameters]; XCTAssertNotNil(params); - + NSString *expectedApiId = [NSString stringWithFormat:@"%ld", (long)MSALTelemetryApiIdAcquireSilentWithUserAndAuthority]; XCTAssertEqualObjects(params.telemetryApiId, expectedApiId); XCTAssertEqualObjects(params.accountIdentifier.displayableId, @"user@contoso.com"); XCTAssertEqualObjects(params.accountIdentifier.homeAccountId, @"1.1234-5678-90abcdefg"); XCTAssertEqualObjects(params.extraURLQueryParameters, (@{ @"slice" : @"slice", @"dc" : @"dc" })); - XCTAssertEqualObjects(params.authority.url.absoluteString, @"https://login.microsoft.com/1234-5678-90abcdefg"); + XCTAssertEqualObjects(params.authority.url.absoluteString, @"https://login.microsoftonline.com/1234-5678-90abcdefg"); XCTAssertFalse(obj.forceRefresh); @@ -1073,14 +1089,27 @@ - (void)testAcquireSilentScopesUserAuthority completionBlock(nil, nil); }]; - authority = [@"https://login.microsoft.com/common" msalAuthority]; + MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"user@contoso.com" - name:@"name" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountId environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; + + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:@"https://login.microsoftonline.com/1234-5678-90abcdefg"] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] + homeAccountId:@"1.1234-5678-90abcdefg" + clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; + + application.accountMetadataCache = self.accountMetadataCache; + application.msalOauth2Provider = [MSALOauth2ProviderFactory oauthProviderForAuthority:authority + clientId:UNIT_TEST_CLIENT_ID + tokenCache:self.tokenCacheAccessor + accountMetadataCache:self.accountMetadataCache + context:nil + error:nil]; + [application acquireTokenSilentForScopes:@[@"fakescope1", @"fakescope2"] account:account @@ -1093,6 +1122,55 @@ - (void)testAcquireSilentScopesUserAuthority } +- (void)testAcquireTokenSilent_whenNoAuthority_andCommonAuthorityInPublicClientApplication_andNoAccountMetadata_shouldUseHomeAuthority +{ + NSError *error = nil; + __auto_type authority = [@"https://login.microsoftonline.com/common" msalAuthority]; + + MSALPublicClientApplicationConfig *config = [[MSALPublicClientApplicationConfig alloc] initWithClientId:UNIT_TEST_CLIENT_ID + redirectUri:nil + authority:authority]; + __auto_type application = [[MSALPublicClientApplication alloc] initWithConfiguration:config + error:&error]; + + XCTAssertNotNil(application); + XCTAssertNil(error); + + [MSIDTestSwizzle instanceMethod:@selector(acquireToken:) + class:[MSIDSilentController class] + block:(id)^(MSIDSilentController *obj, MSIDRequestCompletionBlock completionBlock) + { + XCTAssertTrue([obj isKindOfClass:[MSIDSilentController class]]); + + MSIDRequestParameters *params = [obj requestParameters]; + XCTAssertNotNil(params); + XCTAssertEqualObjects(params.authority.url.absoluteString, @"https://login.microsoftonline.com/1234-5678-90abcdefg"); + completionBlock(nil, nil); + }]; + + MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; + + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"user@contoso.com" + homeAccountId:accountId + environment:@"login.microsoftonline.com" + tenantProfiles:nil]; + + application.accountMetadataCache = self.accountMetadataCache; + application.msalOauth2Provider = [MSALOauth2ProviderFactory oauthProviderForAuthority:authority + clientId:UNIT_TEST_CLIENT_ID + tokenCache:self.tokenCacheAccessor + accountMetadataCache:self.accountMetadataCache + context:nil + error:nil]; + [application acquireTokenSilentForScopes:@[@"fakescope1", @"fakescope2"] + account:account + completionBlock:^(MSALResult *result, NSError *error) + { + XCTAssertNil(result); + XCTAssertNotNil(error); + }]; +} + - (void)testAcquireSilentScopesUser_whenNoAuthority_andCommonAuthorityInPublicClientApplication_shouldUseAccountHomeAuthority { NSError *error = nil; @@ -1114,10 +1192,10 @@ - (void)testAcquireSilentScopesUser_whenNoAuthority_andCommonAuthorityInPublicCl block:(id)^(MSIDSilentController *obj, MSIDRequestCompletionBlock completionBlock) { XCTAssertTrue([obj isKindOfClass:[MSIDSilentController class]]); - + MSIDRequestParameters *params = [obj requestParameters]; XCTAssertNotNil(params); - + NSString *expectedApiId = [NSString stringWithFormat:@"%ld", (long)MSALTelemetryApiIdAcquireSilentWithUser]; XCTAssertEqualObjects(params.telemetryApiId, expectedApiId); XCTAssertEqualObjects(params.accountIdentifier.displayableId, @"user@contoso.com"); @@ -1137,12 +1215,23 @@ - (void)testAcquireSilentScopesUser_whenNoAuthority_andCommonAuthorityInPublicCl completionBlock(nil, nil); }]; + MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"user@contoso.com" - name:@"name" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountId environment:@"login.microsoftonline.com" - tenantId:@"custom_guest_tenant"]; + tenantProfiles:nil]; + + application.accountMetadataCache = self.accountMetadataCache; + application.msalOauth2Provider = [MSALOauth2ProviderFactory oauthProviderForAuthority:authority + clientId:UNIT_TEST_CLIENT_ID + tokenCache:self.tokenCacheAccessor + accountMetadataCache:self.accountMetadataCache + context:nil + error:nil]; + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:@"https://login.microsoftonline.com/1234-5678-90abcdefg"] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountId.identifier clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; [application acquireTokenSilentForScopes:@[@"fakescope1", @"fakescope2"] account:account @@ -1175,10 +1264,10 @@ - (void)testAcquireSilentScopesUser_whenNoAuthority_andNonCommonAuthorityInPubli block:(id)^(MSIDSilentController *obj, MSIDRequestCompletionBlock completionBlock) { XCTAssertTrue([obj isKindOfClass:[MSIDSilentController class]]); - + MSIDRequestParameters *params = [obj requestParameters]; XCTAssertNotNil(params); - + NSString *expectedApiId = [NSString stringWithFormat:@"%ld", (long)MSALTelemetryApiIdAcquireSilentWithUser]; XCTAssertEqualObjects(params.telemetryApiId, expectedApiId); XCTAssertEqualObjects(params.accountIdentifier.displayableId, @"user@contoso.com"); @@ -1198,12 +1287,12 @@ - (void)testAcquireSilentScopesUser_whenNoAuthority_andNonCommonAuthorityInPubli completionBlock(nil, nil); }]; + MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"user@contoso.com" - name:@"name" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountId environment:@"login.microsoftonline.com" - tenantId:@"custom_guest_tenant"]; + tenantProfiles:nil]; [application acquireTokenSilentForScopes:@[@"fakescope1", @"fakescope2"] account:account @@ -1236,10 +1325,10 @@ - (void)testAcquireSilentScopesUser_whenNilAuthority_andNonCommonAuthorityInPubl block:(id)^(MSIDSilentController *obj, MSIDRequestCompletionBlock completionBlock) { XCTAssertTrue([obj isKindOfClass:[MSIDSilentController class]]); - + MSIDRequestParameters *params = [obj requestParameters]; XCTAssertNotNil(params); - + NSString *expectedApiId = [NSString stringWithFormat:@"%ld", (long)MSALTelemetryApiIdAcquireSilentWithUserAndAuthority]; XCTAssertEqualObjects(params.telemetryApiId, expectedApiId); XCTAssertEqualObjects(params.accountIdentifier.displayableId, @"user@contoso.com"); @@ -1259,12 +1348,12 @@ - (void)testAcquireSilentScopesUser_whenNilAuthority_andNonCommonAuthorityInPubl completionBlock(nil, nil); }]; + MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"user@contoso.com" - name:@"name" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountId environment:@"login.microsoftonline.com" - tenantId:@"custom_guest_tenant"]; + tenantProfiles:nil]; [application acquireTokenSilentForScopes:@[@"fakescope1", @"fakescope2"] account:account @@ -1300,17 +1389,17 @@ - (void)testAcquireSilentScopesUserAuthorityForceRefreshCorrelationId block:(id)^(MSIDSilentController *obj, MSIDRequestCompletionBlock completionBlock) { XCTAssertTrue([obj isKindOfClass:[MSIDSilentController class]]); - + MSIDRequestParameters *params = [obj requestParameters]; XCTAssertNotNil(params); - + NSString *expectedApiId = [NSString stringWithFormat:@"%ld", (long)MSALTelemetryApiIdAcquireSilentWithUserAuthorityForceRefreshAndCorrelationId]; XCTAssertEqualObjects(params.telemetryApiId, expectedApiId); XCTAssertEqualObjects(params.accountIdentifier.displayableId, @"user@contoso.com"); XCTAssertEqualObjects(params.accountIdentifier.homeAccountId, @"1.1234-5678-90abcdefg"); XCTAssertEqualObjects(params.extraURLQueryParameters, (@{ @"slice" : @"slice", @"dc" : @"dc" })); - XCTAssertEqualObjects(params.authority.url.absoluteString, @"https://login.microsoft.com/1234-5678-90abcdefg"); + XCTAssertEqualObjects(params.authority.url.absoluteString, @"https://login.microsoftonline.com/1234-5678-90abcdefg"); XCTAssertTrue(obj.forceRefresh); @@ -1324,14 +1413,30 @@ - (void)testAcquireSilentScopesUserAuthorityForceRefreshCorrelationId completionBlock(nil, nil); }]; + MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"user@contoso.com" - name:@"name" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountId environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; - - authority = [@"https://login.microsoft.com/common" msalAuthority]; + tenantProfiles:nil]; + + application.accountMetadataCache = self.accountMetadataCache; + application.msalOauth2Provider = [MSALOauth2ProviderFactory oauthProviderForAuthority:authority + clientId:UNIT_TEST_CLIENT_ID + tokenCache:self.tokenCacheAccessor + accountMetadataCache:self.accountMetadataCache + context:nil + error:nil]; + application.msalOauth2Provider = [MSALOauth2ProviderFactory oauthProviderForAuthority:authority + clientId:UNIT_TEST_CLIENT_ID + tokenCache:self.tokenCacheAccessor + accountMetadataCache:self.accountMetadataCache + context:nil + error:nil]; + + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:@"https://login.microsoftonline.com/1234-5678-90abcdefg"] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] homeAccountId:accountId.identifier clientId:UNIT_TEST_CLIENT_ID instanceAware:NO context:nil error:nil]; [application acquireTokenSilentForScopes:@[@"fakescope1", @"fakescope2"] account:account @@ -1385,6 +1490,8 @@ - (void)testAllAccounts_whenAccountExists_shouldReturnAccountNoError XCTAssertEqualObjects(account.homeAccountId.identifier, @"myuid.utid"); XCTAssertEqualObjects(account.homeAccountId.objectId, @"myuid"); XCTAssertEqualObjects(account.homeAccountId.tenantId, @"utid"); + XCTAssertEqual(account.tenantProfiles.count, 1); + XCTAssertTrue(account.tenantProfiles[0].isHomeTenantProfile); } - (void)testAllAccounts_when2AccountExists_shouldReturn2Accounts @@ -1396,19 +1503,30 @@ - (void)testAllAccounts_when2AccountExists_shouldReturn2Accounts application.tokenCache = self.tokenCacheAccessor; NSError *error = nil; - NSArray *accounts = [application allAccounts:&error]; + NSArray *accounts = [application allAccounts:&error]; XCTAssertNil(error); XCTAssertNotNil(accounts); XCTAssertEqual([accounts count], 2); - MSALAccount *account = accounts[0]; + MSALAccount *account; + MSALAccount *account2; + if ([@"login.microsoftonline.com" isEqualToString:accounts[0].environment]) + { + account = accounts[0]; + account2 = accounts[1]; + } + else + { + account = accounts[1]; + account2 = accounts[0]; + } + XCTAssertEqualObjects(account.username, @"fakeuser@contoso.com"); XCTAssertEqualObjects(account.environment, @"login.microsoftonline.com"); XCTAssertEqualObjects(account.homeAccountId.identifier, @"myuid.utid"); XCTAssertEqualObjects(account.homeAccountId.objectId, @"myuid"); XCTAssertEqualObjects(account.homeAccountId.tenantId, @"utid"); - MSALAccount *account2 = accounts[1]; XCTAssertEqualObjects(account2.username, @"fakeuser@contoso.com"); XCTAssertEqualObjects(account2.environment, @"example.com"); XCTAssertEqualObjects(account2.homeAccountId.identifier, @"myuid.utid"); @@ -1421,7 +1539,7 @@ - (void)testAllAccount_whenFociTokenExistsForOtherClient_andAppMetadataWithSameF //store at & rt in cache with foci flag MSIDAADV2TokenResponse *msidResponse = [self msalDefaultTokenResponseWithAuthority:@"https://login.microsoftonline.com/common" familyId:@"1"]; MSIDConfiguration *configuration = [self msalDefaultConfigurationWithAuthority:@"https://login.microsoftonline.com/common"]; - + BOOL result = [self.tokenCacheAccessor saveTokensWithConfiguration:configuration response:msidResponse factory:[MSIDAADV2Oauth2Factory new] @@ -1429,7 +1547,7 @@ - (void)testAllAccount_whenFociTokenExistsForOtherClient_andAppMetadataWithSameF error:nil]; XCTAssertTrue(result); XCTAssertEqual([[self.tokenCacheAccessor allTokensWithContext:nil error:nil] count], 4); - + NSString *clientId = @"myclient"; [self.tokenCacheAccessor updateAppMetadataWithFamilyId:@"1" clientId:clientId authority:configuration.authority context:nil error:nil]; @@ -1437,15 +1555,15 @@ - (void)testAllAccount_whenFociTokenExistsForOtherClient_andAppMetadataWithSameF // Retrieve cache for a different clientId NSArray *override = @[ @{ @"CFBundleURLSchemes" : @[@"msalmyclient"] } ]; [MSALTestBundle overrideObject:override forKey:@"CFBundleURLTypes"]; - + NSError *appError = nil; __auto_type application = [[MSALPublicClientApplication alloc] initWithClientId:clientId error:&appError]; XCTAssertNil(appError); application.tokenCache = self.tokenCacheAccessor; - + NSError *error = nil; NSArray *allAccounts = [application allAccounts:&error]; - + XCTAssertNil(error); XCTAssertNotNil(allAccounts); XCTAssertEqual([allAccounts count], 1); @@ -1456,7 +1574,7 @@ - (void)testAllAccount_whenFociTokenExistsForOtherClient_andAppMetadataWithNoFam //store at & rt in cache with foci flag MSIDAADV2TokenResponse *msidResponse = [self msalDefaultTokenResponseWithAuthority:@"https://login.microsoftonline.com/common" familyId:@"1"]; MSIDConfiguration *configuration = [self msalDefaultConfigurationWithAuthority:@"https://login.microsoftonline.com/common"]; - + NSError *error = nil; BOOL result = [self.tokenCacheAccessor saveTokensWithConfiguration:configuration response:msidResponse @@ -1465,7 +1583,7 @@ - (void)testAllAccount_whenFociTokenExistsForOtherClient_andAppMetadataWithNoFam error:&error]; XCTAssertTrue(result); XCTAssertEqual([[self.tokenCacheAccessor allTokensWithContext:nil error:nil] count], 4); - + NSString *clientId = @"myclient"; [self.tokenCacheAccessor updateAppMetadataWithFamilyId:@"" clientId:clientId authority:configuration.authority context:nil error:nil]; @@ -1473,14 +1591,14 @@ - (void)testAllAccount_whenFociTokenExistsForOtherClient_andAppMetadataWithNoFam // Retrieve cache for a different clientId NSArray *override = @[ @{ @"CFBundleURLSchemes" : @[@"msalmyclient"] } ]; [MSALTestBundle overrideObject:override forKey:@"CFBundleURLTypes"]; - + NSError *appError = nil; __auto_type application = [[MSALPublicClientApplication alloc] initWithClientId:clientId error:&appError]; XCTAssertNil(appError); application.tokenCache = self.tokenCacheAccessor; - + NSArray *allAccounts = [application allAccounts:&error]; - + XCTAssertNil(error); XCTAssertNotNil(allAccounts); XCTAssertEqual([allAccounts count], 0); @@ -1491,7 +1609,7 @@ - (void)testAllAccount_whenAccountExistsForOtherClient_andNotFociClient_shouldRe //store at & rt in cache with foci flag MSIDAADV2TokenResponse *msidResponse = [self msalDefaultTokenResponseWithAuthority:@"https://login.microsoftonline.com/common" familyId:nil]; MSIDConfiguration *configuration = [self msalDefaultConfigurationWithAuthority:@"https://login.microsoftonline.com/common"]; - + NSError *error = nil; BOOL result = [self.tokenCacheAccessor saveTokensWithConfiguration:configuration response:msidResponse @@ -1502,18 +1620,18 @@ - (void)testAllAccount_whenAccountExistsForOtherClient_andNotFociClient_shouldRe XCTAssertEqual([[self.tokenCacheAccessor allTokensWithContext:nil error:nil] count], 3); NSString *clientId = @"myclient"; - + // Retrieve cache for a different clientId NSArray *override = @[ @{ @"CFBundleURLSchemes" : @[@"msalmyclient"] } ]; [MSALTestBundle overrideObject:override forKey:@"CFBundleURLTypes"]; - + NSError *appError = nil; __auto_type application = [[MSALPublicClientApplication alloc] initWithClientId:clientId error:&appError]; XCTAssertNil(appError); application.tokenCache = self.tokenCacheAccessor; - + NSArray *allAccounts = [application allAccounts:&error]; - + XCTAssertNil(error); XCTAssertNotNil(allAccounts); XCTAssertEqual([allAccounts count], 0); @@ -1534,20 +1652,20 @@ - (void)testAllAccountsFilteredByAuthority_when2AccountExists_shouldReturnAccoun XCTestExpectation *expectation = [self expectationWithDescription:@"Process Metadata."]; [application allAccountsFilteredByAuthority:^(NSArray *accounts, NSError *error) - { - XCTAssertNil(error); - XCTAssertNotNil(accounts); - XCTAssertEqual([accounts count], 1); - - MSALAccount *account = accounts[0]; - XCTAssertEqualObjects(account.username, @"fakeuser@contoso.com"); - XCTAssertEqualObjects(account.environment, @"login.microsoftonline.com"); - XCTAssertEqualObjects(account.homeAccountId.identifier, @"myuid.utid"); - XCTAssertEqualObjects(account.homeAccountId.objectId, @"myuid"); - XCTAssertEqualObjects(account.homeAccountId.tenantId, @"utid"); - - [expectation fulfill]; - }]; + { + XCTAssertNil(error); + XCTAssertNotNil(accounts); + XCTAssertEqual([accounts count], 1); + + MSALAccount *account = accounts[0]; + XCTAssertEqualObjects(account.username, @"fakeuser@contoso.com"); + XCTAssertEqualObjects(account.environment, @"login.microsoftonline.com"); + XCTAssertEqualObjects(account.homeAccountId.identifier, @"myuid.utid"); + XCTAssertEqualObjects(account.homeAccountId.objectId, @"myuid"); + XCTAssertEqualObjects(account.homeAccountId.tenantId, @"utid"); + + [expectation fulfill]; + }]; [self waitForExpectationsWithTimeout:1 handler:nil]; } @@ -1594,10 +1712,13 @@ - (void)testAccountWithHomeAccountId_whenAccountExists_shouldReturnAccountNoErro NSString *homeAccountId = @"myuid.utid"; NSError *error; - __auto_type account = [application accountForHomeAccountId:homeAccountId error:&error]; + MSALAccountEnumerationParameters *parameters = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:homeAccountId]; + __auto_type accounts = [application accountsForParameters:parameters error:&error]; XCTAssertNil(error); - XCTAssertNotNil(account); + XCTAssertNotNil(accounts); + XCTAssertEqual([accounts count], 1); + MSALAccount *account = accounts[0]; XCTAssertEqualObjects(account.username, @"fakeuser@contoso.com"); XCTAssertEqualObjects(account.environment, @"login.microsoftonline.com"); XCTAssertEqualObjects(account.homeAccountId.identifier, @"myuid.utid"); @@ -1615,10 +1736,11 @@ - (void)testAccountWithHomeAccountId_whenAccountExistsButNotMatching_shouldRetur NSString *homeAccountId = @"other_uid.other_utid"; NSError *error; - __auto_type account = [application accountForHomeAccountId:homeAccountId error:&error]; + MSALAccountEnumerationParameters *parameters = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:homeAccountId]; + __auto_type accounts = [application accountsForParameters:parameters error:&error]; XCTAssertNil(error); - XCTAssertNil(account); + XCTAssertEqual([accounts count], 0); } - (void)testAccountWithHomeAccountId_whenFociTokenExistsForOtherClient_andAppMetadataInCache_shouldReturnAccountNoError @@ -1626,7 +1748,7 @@ - (void)testAccountWithHomeAccountId_whenFociTokenExistsForOtherClient_andAppMet //store at & rt in cache with foci flag MSIDAADV2TokenResponse *msidResponse = [self msalDefaultTokenResponseWithAuthority:@"https://login.microsoftonline.com/common" familyId:@"1"]; MSIDConfiguration *configuration = [self msalDefaultConfigurationWithAuthority:@"https://login.microsoftonline.com/common"]; - + NSError *error = nil; BOOL result = [self.tokenCacheAccessor saveTokensWithConfiguration:configuration response:msidResponse @@ -1635,9 +1757,9 @@ - (void)testAccountWithHomeAccountId_whenFociTokenExistsForOtherClient_andAppMet error:&error]; XCTAssertTrue(result); XCTAssertEqual([[self.tokenCacheAccessor allTokensWithContext:nil error:nil] count], 4); - + NSString *clientId = @"myclient"; - + MSIDAppMetadataCacheItem *appMetadata = [MSIDAppMetadataCacheItem new]; appMetadata.clientId = clientId; appMetadata.environment = @"login.microsoftonline.com"; @@ -1648,17 +1770,19 @@ - (void)testAccountWithHomeAccountId_whenFociTokenExistsForOtherClient_andAppMet // Retrieve cache for a different clientId NSArray *override = @[ @{ @"CFBundleURLSchemes" : @[@"msalmyclient"] } ]; [MSALTestBundle overrideObject:override forKey:@"CFBundleURLTypes"]; - + NSError *appError = nil; __auto_type application = [[MSALPublicClientApplication alloc] initWithClientId:clientId error:&appError]; XCTAssertNil(appError); application.tokenCache = self.tokenCacheAccessor; - + NSString *homeAccountId = @"myuid.utid"; - __auto_type account = [application accountForHomeAccountId:homeAccountId error:&error]; - + MSALAccountEnumerationParameters *parameters = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:homeAccountId]; + __auto_type accounts = [application accountsForParameters:parameters error:&error]; + XCTAssertNil(error); - XCTAssertNotNil(account); + XCTAssertNotNil(accounts); + XCTAssertTrue([accounts count]); } #pragma mark - loadAccountForUsername @@ -1703,7 +1827,7 @@ - (void)testAccountWithUsername_whenFociTokenExistsForOtherClient_andNoAppMetada //store at & rt in cache with foci flag MSIDAADV2TokenResponse *msidResponse = [self msalDefaultTokenResponseWithAuthority:@"https://login.microsoftonline.com/common" familyId:@"1"]; MSIDConfiguration *configuration = [self msalDefaultConfigurationWithAuthority:@"https://login.microsoftonline.com/common"]; - + NSError *error = nil; BOOL result = [self.tokenCacheAccessor saveTokensWithConfiguration:configuration response:msidResponse @@ -1712,19 +1836,19 @@ - (void)testAccountWithUsername_whenFociTokenExistsForOtherClient_andNoAppMetada error:&error]; XCTAssertTrue(result); XCTAssertEqual([[self.tokenCacheAccessor allTokensWithContext:nil error:nil] count], 4); - + // Retrieve cache for a different clientId NSArray *override = @[ @{ @"CFBundleURLSchemes" : @[@"msalmyclient"] } ]; [MSALTestBundle overrideObject:override forKey:@"CFBundleURLTypes"]; - + NSString *clientId = @"myclient"; NSError *appError = nil; __auto_type application = [[MSALPublicClientApplication alloc] initWithClientId:clientId error:&appError]; XCTAssertNil(appError); application.tokenCache = self.tokenCacheAccessor; - + __auto_type account = [application accountForUsername:@"fakeuser@contoso.com" error:&error]; - + XCTAssertNil(error); XCTAssertNotNil(account); } @@ -1746,7 +1870,7 @@ - (void)testRemoveAccount_whenAccountExists_shouldRemoveAccount MSIDAccount *account = [[MSIDAADV2Oauth2Factory new] accountFromResponse:[self msalDefaultTokenResponse] configuration:[self msalDefaultConfiguration]]; - MSALAccount *msalAccount = [[MSALAccount alloc] initWithMSIDAccount:account]; + MSALAccount *msalAccount = [[MSALAccount alloc] initWithMSIDAccount:account createTenantProfile:NO]; XCTAssertEqualObjects([application allAccounts:nil][0], msalAccount); @@ -1760,95 +1884,104 @@ - (void)testRemoveAccount_whenAccountExists_shouldRemoveAccount XCTAssertEqual([application allAccounts:nil].count, 0); } + - (void)testRemoveAccount_whenAccountExists_andIsFociClient_shouldRemoveAccount_andMarkClientNonFoci { // 1. Save response for a different clientId NSString *authorityUrl = @"https://login.microsoftonline.com/utid"; MSIDAADV2TokenResponse *msidResponse = [self msalDefaultTokenResponseWithAuthority:authorityUrl familyId:@"1"]; MSIDConfiguration *configuration = [self msalDefaultConfigurationWithAuthority:authorityUrl]; - + BOOL result = [self.tokenCacheAccessor saveTokensWithConfiguration:configuration response:msidResponse factory:[MSIDAADV2Oauth2Factory new] context:nil error:nil]; - + XCTAssertTrue(result); XCTAssertEqual([[self.tokenCacheAccessor allTokensWithContext:nil error:nil] count], 4); // 2. Create PublicClientApplication for a different app NSArray *override = @[ @{ @"CFBundleURLSchemes" : @[@"msalmyclient"] } ]; [MSALTestBundle overrideObject:override forKey:@"CFBundleURLTypes"]; - + MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] initWithClientId:@"myclient" error:nil]; application.tokenCache = self.tokenCacheAccessor; [self.tokenCacheAccessor updateAppMetadataWithFamilyId:@"1" clientId:@"myclient" authority:configuration.authority context:nil error:nil]; - MSIDAuthority *authority = [MSIDAuthorityFactory authorityFromUrl:[NSURL URLWithString:authorityUrl] context:nil error:nil]; - + MSIDAuthority *authority = [authorityUrl aadAuthority]; + configuration = [[MSIDConfiguration alloc] initWithAuthority:authority redirectUri:UNIT_TEST_DEFAULT_REDIRECT_URI clientId:@"myclient" target:@"fakescope1 fakescope2"]; - + MSIDAccount *account = [[MSIDAADV2Oauth2Factory new] accountFromResponse:msidResponse configuration:configuration]; - MSALAccount *msalAccount = [[MSALAccount alloc] initWithMSIDAccount:account]; - + MSALAccount *msalAccount = [[MSALAccount alloc] initWithMSIDAccount:account createTenantProfile:NO]; + XCTAssertEqualObjects([application allAccounts:nil][0], msalAccount); - + // 3. Remove account NSError *error = nil; result = [application removeAccount:msalAccount error:&error]; - + XCTAssertTrue(result); XCTAssertNil(error); - + // 4. Make sure the account is now gone XCTAssertEqual([application allAccounts:nil].count, 0); - + // 5. Make sure account and FOCI tokens are still in cache - MSIDAccount *cachedAccount = [self.tokenCacheAccessor getAccountForIdentifier:account.accountIdentifier authority:account.authority context:nil error:nil]; + MSIDAccount *cachedAccount = [self.tokenCacheAccessor getAccountForIdentifier:account.accountIdentifier authority:authority context:nil error:nil]; XCTAssertNotNil(cachedAccount); - + MSIDRefreshToken *fociToken = [self.tokenCacheAccessor getRefreshTokenWithAccount:account.accountIdentifier familyId:@"1" configuration:configuration context:nil error:nil]; XCTAssertNotNil(fociToken); - + MSIDRefreshToken *mrrtToken = [self.tokenCacheAccessor getRefreshTokenWithAccount:account.accountIdentifier familyId:nil configuration:configuration context:nil error:nil]; XCTAssertNil(mrrtToken); - + [self msalAddDiscoveryResponse:authorityUrl appendDefaultHeaders:YES]; - + // 5. Try to acquire token silently, expecting to get interaction required back // That means FOCI wasn't used by the app although present XCTestExpectation *expectation = [self expectationWithDescription:@"Acquire token silent"]; - + + // Save account metadata authority map from common to the specific tenant id. + [self.accountMetadataCache updateAuthorityURL:[NSURL URLWithString:authorityUrl] + forRequestURL:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] + homeAccountId:account.accountIdentifier.homeAccountId + clientId:@"myclient" instanceAware:NO context:nil error:nil]; + [application acquireTokenSilentForScopes:@[@"fakescope1"] account:msalAccount completionBlock:^(MSALResult * _Nullable result, NSError * _Nullable error) { - - + + XCTAssertNil(result); XCTAssertNotNil(error); XCTAssertEqual(error.code, MSALErrorInteractionRequired); [expectation fulfill]; - }]; - + }]; + [self waitForExpectationsWithTimeout:1.0 handler:nil]; } #endif +#if TARGET_OS_IPHONE + - (void)testRemove_whenUserDontExist_shouldReturnTrueWithNoError { __auto_type application = [[MSALPublicClientApplication alloc] initWithClientId:UNIT_TEST_CLIENT_ID error:nil]; + MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"1.1234-5678-90abcdefg" objectId:@"1" tenantId:@"1234-5678-90abcdefg"]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"user@contoso.com" - name:@"name" - homeAccountId:@"1.1234-5678-90abcdefg" - localAccountId:@"1" + homeAccountId:accountId environment:@"login.microsoftonline.com" - tenantId:@"1234-5678-90abcdefg"]; + tenantProfiles:nil]; NSError *error; BOOL result = [application removeAccount:account error:&error]; @@ -1857,11 +1990,14 @@ - (void)testRemove_whenUserDontExist_shouldReturnTrueWithNoError XCTAssertNil(error); } +#endif + - (void)testRemoveUser_whenKeychainError_shouldReturnNoWithError { __auto_type application = [[MSALPublicClientApplication alloc] initWithClientId:UNIT_TEST_CLIENT_ID error:nil]; - MSALAccount *account = [MSALAccount new]; + MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"uid.utid" objectId:@"uid" tenantId:@"utid"]; + MSALAccount *account = [[MSALAccount alloc] initWithUsername:nil homeAccountId:accountId environment:@"contoso.com" tenantProfiles:nil]; [MSIDTestSwizzle instanceMethod:@selector(clearCacheForAccount:authority:clientId:familyId:context:error:) class:[MSIDDefaultTokenCacheAccessor class] @@ -1920,17 +2056,20 @@ - (void)msalAddDiscoveryResponse:(NSString *)authority appendDefaultHeaders:(BOO MSIDTestURLResponse *response = [MSIDTestURLResponse request:requestUrl reponse:httpResponse]; NSMutableDictionary *headers = [[MSIDDeviceId deviceId] mutableCopy]; - + if (appendDefaultHeaders) { [headers addEntriesFromDictionary:[MSIDTestURLResponse msidDefaultRequestHeaders]]; } - + headers[@"Accept"] = @"application/json"; headers[@"x-ms-PkeyAuth"] = @"1.0"; response->_requestHeaders = headers; + + NSString *endpoint = [NSString stringWithFormat:@"%@/v2.0/.well-known/openid-configuration", authority]; + __auto_type responseJson = @{ - @"tenant_discovery_endpoint" : @"https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration", + @"tenant_discovery_endpoint" : endpoint, @"metadata" : @[ @{ @"preferred_network" : @"login.microsoftonline.com", @@ -1955,29 +2094,29 @@ - (MSIDAADV2TokenResponse *)msalDefaultTokenResponseWithAuthority:(NSString *)au - (MSIDAADV2TokenResponse *)msalDefaultTokenResponseWithAuthority:(NSString *)authorityString familyId:(NSString *)familyId { - NSDictionary* idTokenClaims = @{ @"home_oid" : @"myuid", @"preferred_username": @"fakeuser@contoso.com"}; + NSDictionary* idTokenClaims = @{ @"home_oid" : @"myuid", @"preferred_username": @"fakeuser@contoso.com", @"tid": @"utid"}; NSDictionary* clientInfoClaims = @{ @"uid" : @"myuid", @"utid" : @"utid"}; NSString *rawIdToken = [NSString stringWithFormat:@"fakeheader.%@.fakesignature", [NSString msidBase64UrlEncodedStringFromData:[NSJSONSerialization dataWithJSONObject:idTokenClaims options:0 error:nil]]]; NSString *rawClientInfo = [NSString msidBase64UrlEncodedStringFromData:[NSJSONSerialization dataWithJSONObject:clientInfoClaims options:0 error:nil]]; - + NSMutableDictionary *responseDict = [@{ - @"access_token": @"access_token", - @"refresh_token": @"fakeRefreshToken", - @"authority" : authorityString, - @"scope": @"fakescope1 fakescope2", - @"client_id": UNIT_TEST_CLIENT_ID, - @"id_token": rawIdToken, - @"client_info": rawClientInfo, - @"expires_on" : @"1" - } mutableCopy]; - + @"access_token": @"access_token", + @"refresh_token": @"fakeRefreshToken", + @"authority" : authorityString, + @"scope": @"fakescope1 fakescope2", + @"client_id": UNIT_TEST_CLIENT_ID, + @"id_token": rawIdToken, + @"client_info": rawClientInfo, + @"expires_on" : @"1" + } mutableCopy]; + if (familyId) { responseDict[@"foci"] = familyId; } - + MSIDAADV2TokenResponse *msidResponse = [[MSIDAADV2TokenResponse alloc] initWithJSONDictionary:responseDict error:nil]; @@ -1987,7 +2126,7 @@ - (MSIDAADV2TokenResponse *)msalDefaultTokenResponseWithAuthority:(NSString *)au - (MSIDConfiguration *)msalDefaultConfiguration { - MSIDAuthority *authority = [MSIDAuthorityFactory authorityFromUrl:[NSURL URLWithString:@"https://login.microsoftonline.com/common"] context:nil error:nil]; + MSIDAuthority *authority = [@"https://login.microsoftonline.com/common" aadAuthority]; return [[MSIDConfiguration alloc] initWithAuthority:authority redirectUri:UNIT_TEST_DEFAULT_REDIRECT_URI @@ -1997,7 +2136,7 @@ - (MSIDConfiguration *)msalDefaultConfiguration - (MSIDConfiguration *)msalDefaultConfigurationWithAuthority:(NSString *)authorityString { - MSIDAuthority *authority = [MSIDAuthorityFactory authorityFromUrl:[NSURL URLWithString:authorityString] context:nil error:nil]; + MSIDAuthority *authority = [authorityString aadAuthority]; return [[MSIDConfiguration alloc] initWithAuthority:authority redirectUri:UNIT_TEST_DEFAULT_REDIRECT_URI @@ -2006,3 +2145,4 @@ - (MSIDConfiguration *)msalDefaultConfigurationWithAuthority:(NSString *)authori } @end + diff --git a/MSAL/test/unit/MSALResultTests.m b/MSAL/test/unit/MSALResultTests.m index a0561bdd32..66a609a4cd 100644 --- a/MSAL/test/unit/MSALResultTests.m +++ b/MSAL/test/unit/MSALResultTests.m @@ -32,6 +32,14 @@ #import "NSString+MSIDTestUtil.h" #import "MSIDAccountIdentifier.h" #import "MSIDAADV2IdTokenClaims.h" +#import "MSALTenantProfile.h" +#import "MSALAuthority.h" +#import "MSALAccount.h" +#import "MSALAccountId.h" +#import "MSALResult+Internal.h" +#import "MSALAADAuthority.h" +#import "MSALAuthority_Internal.h" +#import "MSALAccount+MultiTenantAccount.h" @interface MSALResultTests : MSALTestCase @@ -54,7 +62,8 @@ - (void)testMSALResultWithTokenResult_whenTokenResultIsNil_shouldReturnError MSIDTokenResult *tokenResult = nil; NSError *error = nil; - MSALResult *result = [MSALResult resultWithTokenResult:tokenResult error:&error]; + MSALAADAuthority *authority = [[MSALAADAuthority alloc] initWithURL:[NSURL URLWithString:@"https://my.issuer.com/contoso.com"] error:nil]; + MSALResult *result = [MSALResult resultWithMSIDTokenResult:tokenResult authority:authority error:&error]; XCTAssertNil(result); XCTAssertEqualObjects(error.domain, @"MSIDErrorDomain"); @@ -68,7 +77,8 @@ - (void)testMSALResultWithTokenResult_whenTokenResultContainsInvalidIdToken_shou MSIDTokenResult *tokenResult = [MSIDTokenResult new]; NSError *error = nil; - MSALResult *result = [MSALResult resultWithTokenResult:tokenResult error:&error]; + MSALAADAuthority *authority = [[MSALAADAuthority alloc] initWithURL:[NSURL URLWithString:@"https://my.issuer.com/contoso.com"] error:nil]; + MSALResult *result = [MSALResult resultWithMSIDTokenResult:tokenResult authority:authority error:&error]; XCTAssertNil(result); XCTAssertEqualObjects(error.domain, @"MSIDErrorDomain"); @@ -83,35 +93,53 @@ - (void)testMSALResultWithTokenResult_whenTokenResultContainsNilAuthority_should tokenResult.rawIdToken = @"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0aWQiOiJ0ZW5hbnRfaWQifQ.t3T_3W7IcUfkjxTEUlM4beC1KccZJG7JaCJvTLjYg6M"; NSError *error = nil; - MSALResult *result = [MSALResult resultWithTokenResult:tokenResult error:&error]; + MSALAADAuthority *authority = nil; + MSALResult *result = [MSALResult resultWithMSIDTokenResult:tokenResult authority:authority error:&error]; XCTAssertNil(result); XCTAssertEqualObjects(error.domain, @"MSIDErrorDomain"); - XCTAssertEqual(error.code, MSIDErrorInvalidDeveloperParameter); + XCTAssertEqual(error.code, MSIDErrorInternal); XCTAssertNotNil(error.userInfo); - XCTAssertEqualObjects(error.userInfo[MSIDErrorDescriptionKey], @"Provided authority url is not a valid authority."); + XCTAssertEqualObjects(error.userInfo[MSIDErrorDescriptionKey], @"Nil authority in the result provided"); } - (void)testMSALResultWithTokenResult_whenValidTokenResult_shouldReturnCorrectAttributes { + MSALAADAuthority *msalAuthority = [[MSALAADAuthority alloc] initWithURL:[NSURL URLWithString:@"https://login.microsoftonline.com/tenant_id"] error:nil]; + MSIDTokenResult *tokenResult = [MSIDTokenResult new]; tokenResult.rawIdToken = @"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0aWQiOiJ0ZW5hbnRfaWQifQ.t3T_3W7IcUfkjxTEUlM4beC1KccZJG7JaCJvTLjYg6M"; NSError *claimsError = nil; MSIDAADV2IdTokenClaims *claims = [[MSIDAADV2IdTokenClaims alloc] initWithRawIdToken:tokenResult.rawIdToken error:&claimsError]; - __auto_type authority = [@"https://login.microsoftonline.com/common" authority]; - tokenResult.authority = authority; + __auto_type authority = [@"https://login.microsoftonline.com/tenant_id" aadAuthority]; + tokenResult.authority = msalAuthority.msidAuthority; MSIDAccount *account = [MSIDAccount new]; - account.authority = authority; + account.environment = authority.environment; + account.realm = authority.realm; account.localAccountId = @"local account id"; - account.accountIdentifier = [[MSIDAccountIdentifier alloc] initWithDisplayableId:@"legacy.id" homeAccountId:@"some id"]; + account.accountIdentifier = [[MSIDAccountIdentifier alloc] initWithDisplayableId:@"legacy.id" homeAccountId:@"uid.tenant_id"]; tokenResult.account = account; + tokenResult.correlationId = [[NSUUID alloc] initWithUUIDString:@"00000000-0000-0000-0000-000000000001"]; NSError *error = nil; - MSALResult *result = [MSALResult resultWithTokenResult:tokenResult error:&error]; + MSALResult *result = [MSALResult resultWithMSIDTokenResult:tokenResult authority:msalAuthority error:&error]; XCTAssertNotNil(result); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" XCTAssertEqualObjects(result.tenantId, claims.realm); XCTAssertEqual(result.uniqueId, @"local account id"); +#pragma clang diagnostic pop + XCTAssertNotNil(result.tenantProfile); + XCTAssertEqualObjects(result.tenantProfile.environment, authority.environment); + XCTAssertEqualObjects(result.tenantProfile.tenantId, authority.realm); + XCTAssertEqual(result.tenantProfile.isHomeTenantProfile, YES); + XCTAssertEqualObjects(result.tenantProfile.tenantId, @"tenant_id"); + XCTAssertNotNil(result.tenantProfile.claims); + XCTAssertNotNil(result.account); + XCTAssertEqualObjects(result.account.identifier, @"uid.tenant_id"); + XCTAssertNil(result.account.tenantProfiles); + XCTAssertEqualObjects(tokenResult.correlationId.UUIDString, @"00000000-0000-0000-0000-000000000001"); } @end diff --git a/MSAL/test/unit/MSALTelemetryAggregatedTests.m b/MSAL/test/unit/MSALTelemetryAggregatedTests.m new file mode 100644 index 0000000000..ca7d92bd15 --- /dev/null +++ b/MSAL/test/unit/MSALTelemetryAggregatedTests.m @@ -0,0 +1,559 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALTestCase.h" +#import "MSALTelemetry.h" +#import "MSIDTelemetry+Internal.h" +#import "MSIDTelemetryEventStrings.h" +#import "XCTestCase+HelperMethods.h" +#import "NSData+MSIDExtensions.h" +#import "MSIDTestContext.h" +#import "MSIDTelemetryHttpEvent.h" +#import "MSIDTelemetryAPIEvent.h" +#import "MSIDTelemetryCacheEvent.h" +#import "MSIDTelemetryUIEvent.h" +#import "MSIDTelemetryBrokerEvent.h" +#import "MSIDTelemetryAuthorityValidationEvent.h" +#import "MSALGlobalConfig.h" +#import "MSALTelemetryConfig.h" + +@interface MSALTelemetryAggregatedTests : MSALTestCase + +@property (nonatomic) NSDictionary *receivedEvent; +@property (nonatomic) NSString *requestId; +@property (nonatomic) MSIDTestContext *context; + +@end + +@implementation MSALTelemetryAggregatedTests + +- (void)setUp +{ + [super setUp]; + + MSALGlobalConfig.telemetryConfig.telemetryCallback = ^(NSDictionary *event) + { + self.receivedEvent = event; + }; + + MSALGlobalConfig.telemetryConfig.piiEnabled = NO; + MSIDTelemetry.sharedInstance.notifyOnFailureOnly = NO; + + self.requestId = [[MSIDTelemetry sharedInstance] generateRequestId]; + + __auto_type context = [MSIDTestContext new]; + context.telemetryRequestId = self.requestId; + context.correlationId = [[NSUUID alloc] initWithUUIDString:@"00000000-0000-0000-0000-000000000001"]; + self.context = context; +} + +- (void)tearDown +{ + [super tearDown]; + + MSALGlobalConfig.telemetryConfig.telemetryCallback = nil; + self.receivedEvent = nil; +} + +#pragma mark - flush aggregated + +- (void)testFlush_whenThereIsOneHttpEvent_shouldSendAggregatedEvent +{ + // HTTP event + MSIDTelemetryHttpEvent *httpEvent = [[MSIDTelemetryHttpEvent alloc] initWithName:@"httpEvent" context:self.context]; + [[MSIDTelemetry sharedInstance] startEvent:self.requestId eventName:@"httpEvent"]; + [[MSIDTelemetry sharedInstance] stopEvent:self.requestId event:httpEvent]; + + [[MSIDTelemetry sharedInstance] flush:self.requestId]; + + XCTAssertNotNil(self.receivedEvent); + NSDictionary *eventInfo = self.receivedEvent; +#if TARGET_OS_IPHONE + XCTAssertEqual(eventInfo.count, 10); + XCTAssertNotNil(eventInfo[@"msal.x_client_dm"]); +#else + XCTAssertEqual(eventInfo.count, 9); +#endif + XCTAssertEqualObjects(eventInfo[@"msal.correlation_id"], @"00000000-0000-0000-0000-000000000001"); + XCTAssertEqualObjects(eventInfo[@"msal.http_event_count"], @1); + XCTAssertEqualObjects(eventInfo[@"msal.oauth_error_code"], @""); + XCTAssertNotNil(eventInfo[@"msal.request_id"]); + XCTAssertEqualObjects(eventInfo[@"msal.response_code"], @""); + XCTAssertNotNil(eventInfo[@"msal.x_client_cpu"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_os"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_sku"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_ver"]); +} + +- (void)testFlush_whenThereAreTwoHttpEvents_shouldSendAggregatedEvent +{ + // HTTP event #1 + MSIDTelemetryHttpEvent *httpEvent = [[MSIDTelemetryHttpEvent alloc] initWithName:@"httpEvent" context:self.context]; + [[MSIDTelemetry sharedInstance] startEvent:self.requestId eventName:@"httpEvent"]; + [[MSIDTelemetry sharedInstance] stopEvent:self.requestId event:httpEvent]; + // HTTP event #2 + httpEvent = [[MSIDTelemetryHttpEvent alloc] initWithName:@"httpEvent2" context:self.context]; + [httpEvent setHttpResponseCode:@"200"]; + [httpEvent setProperty:MSID_TELEMETRY_KEY_OAUTH_ERROR_CODE value:@"invalid_grant"]; + [httpEvent setProperty:MSID_TELEMETRY_KEY_SERVER_ERROR_CODE value:@"123"]; + [httpEvent setProperty:MSID_TELEMETRY_KEY_SERVER_SUBERROR_CODE value:@"1234"]; + [httpEvent setProperty:MSID_TELEMETRY_KEY_RT_AGE value:@"255.0643"]; + [httpEvent setProperty:MSID_TELEMETRY_KEY_SPE_INFO value:@"some info"]; + [[MSIDTelemetry sharedInstance] startEvent:self.requestId eventName:@"httpEvent2"]; + [[MSIDTelemetry sharedInstance] stopEvent:self.requestId event:httpEvent]; + + [[MSIDTelemetry sharedInstance] flush:self.requestId]; + + XCTAssertNotNil(self.receivedEvent); + NSDictionary *eventInfo = self.receivedEvent; +#if TARGET_OS_IPHONE + XCTAssertEqual(eventInfo.count, 14); + XCTAssertNotNil(eventInfo[@"msal.x_client_dm"]); +#else + XCTAssertEqual(eventInfo.count, 13); +#endif + XCTAssertEqualObjects(eventInfo[@"msal.correlation_id"], @"00000000-0000-0000-0000-000000000001"); + XCTAssertEqualObjects(eventInfo[@"msal.http_event_count"], @2); + XCTAssertEqualObjects(eventInfo[@"msal.oauth_error_code"], @"invalid_grant"); + XCTAssertNotNil(eventInfo[@"msal.request_id"]); + XCTAssertEqualObjects(eventInfo[@"msal.response_code"], @"200"); + XCTAssertEqualObjects(eventInfo[@"msal.server_error_code"], @"123"); + XCTAssertEqualObjects(eventInfo[@"msal.server_sub_error_code"], @"1234"); + XCTAssertEqualObjects(eventInfo[@"msal.rt_age"], @"255.0643"); + XCTAssertEqualObjects(eventInfo[@"msal.spe_info"], @"some info"); + XCTAssertNotNil(eventInfo[@"msal.x_client_cpu"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_os"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_sku"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_ver"]); +} + +- (void)testFlush_whenThereIsOneApiEvent_shouldSendAggregatedEvent +{ + // API event #1 + __auto_type eventName = @"api event"; + __auto_type event = [[MSIDTelemetryAPIEvent alloc] initWithName:eventName context:self.context]; + [[MSIDTelemetry sharedInstance] startEvent:self.requestId eventName:eventName]; + [[MSIDTelemetry sharedInstance] stopEvent:self.requestId event:event]; + + [[MSIDTelemetry sharedInstance] flush:self.requestId]; + + XCTAssertNotNil(self.receivedEvent); + NSDictionary *eventInfo = self.receivedEvent; +#if TARGET_OS_IPHONE + XCTAssertEqual(eventInfo.count, 8); + XCTAssertNotNil(eventInfo[@"msal.x_client_dm"]); +#else + XCTAssertEqual(eventInfo.count, 7); +#endif + XCTAssertEqualObjects(eventInfo[@"msal.correlation_id"], @"00000000-0000-0000-0000-000000000001"); + XCTAssertNotNil(eventInfo[@"msal.response_time"]); + XCTAssertNotNil(eventInfo[@"msal.request_id"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_cpu"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_os"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_sku"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_ver"]); +} + +- (void)testFlush_whenThereAreTwoApiEvents_shouldSendAggregatedEvent +{ + // API event #1 + __auto_type eventName = @"api event"; + __auto_type event = [[MSIDTelemetryAPIEvent alloc] initWithName:eventName context:self.context]; + [[MSIDTelemetry sharedInstance] startEvent:self.requestId eventName:eventName]; + [[MSIDTelemetry sharedInstance] stopEvent:self.requestId event:event]; + // API event #2 + eventName = @"api event2"; + event = [[MSIDTelemetryAPIEvent alloc] initWithName:eventName context:self.context]; + [event setExtendedExpiresOnSetting:@"no"]; + [event setPromptType:MSIDPromptTypeLogin]; + [event setResultStatus:@"succeeded"]; + [event setProperty:MSID_TELEMETRY_KEY_TENANT_ID value:@"6fd1f5cd-a94c-4335-889b-6c598e6d8048"]; + [event setProperty:MSID_TELEMETRY_KEY_USER_ID value:@"1234"]; + [event setProperty:MSID_TELEMETRY_KEY_CLIENT_ID value:@"c3c7f5e5-7153-44d4-90e6-329686d48d76"]; + [event setProperty:MSID_TELEMETRY_KEY_API_ID value:@"8"]; + [event setProperty:MSID_TELEMETRY_KEY_API_ERROR_CODE value:@"some error code"]; + [event setProperty:MSID_TELEMETRY_KEY_ERROR_DOMAIN value:@"some domain"]; + [event setProperty:MSID_TELEMETRY_KEY_PROTOCOL_CODE value:@"some protocol code"]; + [event setProperty:MSID_TELEMETRY_KEY_IS_SUCCESSFUL value:@"yes"]; + [[MSIDTelemetry sharedInstance] startEvent:self.requestId eventName:eventName]; + [[MSIDTelemetry sharedInstance] stopEvent:self.requestId event:event]; + + [[MSIDTelemetry sharedInstance] flush:self.requestId]; + + XCTAssertNotNil(self.receivedEvent); + NSDictionary *eventInfo = self.receivedEvent; +#if TARGET_OS_IPHONE + XCTAssertEqual(eventInfo.count, 16); + XCTAssertNotNil(eventInfo[@"msal.x_client_dm"]); +#else + XCTAssertEqual(eventInfo.count, 15); +#endif + XCTAssertEqualObjects(eventInfo[@"msal.correlation_id"], @"00000000-0000-0000-0000-000000000001"); + XCTAssertNotNil(eventInfo[@"msal.response_time"]); + XCTAssertNotNil(eventInfo[@"msal.request_id"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_cpu"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_os"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_sku"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_ver"]); + XCTAssertEqualObjects(eventInfo[@"msal.api_error_code"], @"some error code"); + XCTAssertEqualObjects(eventInfo[@"msal.api_id"], @"8"); + XCTAssertEqualObjects(eventInfo[@"msal.error_domain"], @"some domain"); + XCTAssertEqualObjects(eventInfo[@"msal.error_protocol_code"], @"some protocol code"); + XCTAssertEqualObjects(eventInfo[@"msal.extended_expires_on_setting"], @"no"); + XCTAssertEqualObjects(eventInfo[@"msal.is_successfull"], @"yes"); + XCTAssertEqualObjects(eventInfo[@"msal.prompt_behavior"], @"login"); + XCTAssertEqualObjects(eventInfo[@"msal.status"], @"succeeded"); +} + +- (void)testFlush_whenThereIsOneCacheEvent_shouldSendAggregatedEvent +{ + // Cache event #1 + __auto_type eventName = @"cache event"; + __auto_type event = [[MSIDTelemetryCacheEvent alloc] initWithName:eventName context:self.context]; + [[MSIDTelemetry sharedInstance] startEvent:self.requestId eventName:eventName]; + [[MSIDTelemetry sharedInstance] stopEvent:self.requestId event:event]; + + [[MSIDTelemetry sharedInstance] flush:self.requestId]; + + XCTAssertNotNil(self.receivedEvent); + NSDictionary *eventInfo = self.receivedEvent; +#if TARGET_OS_IPHONE + XCTAssertEqual(eventInfo.count, 8); + XCTAssertNotNil(eventInfo[@"msal.x_client_dm"]); +#else + XCTAssertEqual(eventInfo.count, 7); +#endif + XCTAssertEqualObjects(eventInfo[@"msal.correlation_id"], @"00000000-0000-0000-0000-000000000001"); + XCTAssertEqualObjects(eventInfo[@"msal.cache_event_count"], @1); + XCTAssertNotNil(eventInfo[@"msal.request_id"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_cpu"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_os"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_sku"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_ver"]); +} + +- (void)testFlush_whenThereAreTwoCacheEvents_shouldSendAggregatedEvent +{ + // Cache event #1 + __auto_type eventName = @"cache event"; + __auto_type event = [[MSIDTelemetryCacheEvent alloc] initWithName:eventName context:self.context]; + [[MSIDTelemetry sharedInstance] startEvent:self.requestId eventName:eventName]; + [[MSIDTelemetry sharedInstance] stopEvent:self.requestId event:event]; + // Cache event #2 + eventName = @"cache event 2"; + event = [[MSIDTelemetryCacheEvent alloc] initWithName:eventName context:self.context]; + [event setProperty:MSID_TELEMETRY_KEY_RT_STATUS value:@"1"]; + [event setProperty:MSID_TELEMETRY_KEY_FRT_STATUS value:@"2"]; + [event setProperty:MSID_TELEMETRY_KEY_MRRT_STATUS value:@"3"]; + [event setProperty:MSID_TELEMETRY_KEY_SPE_INFO value:@"4"]; + [event setProperty:MSID_TELEMETRY_KEY_WIPE_APP value:@"5"]; + [event setProperty:MSID_TELEMETRY_KEY_WIPE_TIME value:@"6"]; + [[MSIDTelemetry sharedInstance] startEvent:self.requestId eventName:eventName]; + [[MSIDTelemetry sharedInstance] stopEvent:self.requestId event:event]; + + [[MSIDTelemetry sharedInstance] flush:self.requestId]; + + XCTAssertNotNil(self.receivedEvent); + NSDictionary *eventInfo = self.receivedEvent; +#if TARGET_OS_IPHONE + XCTAssertEqual(eventInfo.count, 14); + XCTAssertNotNil(eventInfo[@"msal.x_client_dm"]); +#else + XCTAssertEqual(eventInfo.count, 13); +#endif + XCTAssertEqualObjects(eventInfo[@"msal.correlation_id"], @"00000000-0000-0000-0000-000000000001"); + XCTAssertEqualObjects(eventInfo[@"msal.cache_event_count"], @2); + XCTAssertEqualObjects(eventInfo[@"msal.token_rt_status"], @"1"); + XCTAssertEqualObjects(eventInfo[@"msal.token_frt_status"], @"2"); + XCTAssertEqualObjects(eventInfo[@"msal.token_mrrt_status"], @"3"); + XCTAssertEqualObjects(eventInfo[@"msal.spe_info"], @"4"); + XCTAssertEqualObjects(eventInfo[@"msal.wipe_app"], @"5"); + XCTAssertEqualObjects(eventInfo[@"msal.wipe_time"], @"6"); + XCTAssertNotNil(eventInfo[@"msal.request_id"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_cpu"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_os"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_sku"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_ver"]); +} + +- (void)testFlush_whenThereIsOneUiEvent_shouldSendAggregatedEvent +{ + // UI event #1 + __auto_type eventName = @"UI event"; + __auto_type event = [[MSIDTelemetryUIEvent alloc] initWithName:eventName context:self.context]; + [[MSIDTelemetry sharedInstance] startEvent:self.requestId eventName:eventName]; + [[MSIDTelemetry sharedInstance] stopEvent:self.requestId event:event]; + + [[MSIDTelemetry sharedInstance] flush:self.requestId]; + + XCTAssertNotNil(self.receivedEvent); + NSDictionary *eventInfo = self.receivedEvent; +#if TARGET_OS_IPHONE + XCTAssertEqual(eventInfo.count, 10); + XCTAssertNotNil(eventInfo[@"msal.x_client_dm"]); +#else + XCTAssertEqual(eventInfo.count, 9); +#endif + XCTAssertEqualObjects(eventInfo[@"msal.correlation_id"], @"00000000-0000-0000-0000-000000000001"); + XCTAssertNotNil(eventInfo[@"msal.request_id"]); + XCTAssertEqualObjects(eventInfo[@"msal.ntlm"], @""); + XCTAssertEqualObjects(eventInfo[@"msal.ui_event_count"], @1); + XCTAssertEqualObjects(eventInfo[@"msal.user_cancel"], @""); + XCTAssertNotNil(eventInfo[@"msal.x_client_cpu"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_os"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_sku"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_ver"]); +} + +- (void)testFlush_whenThereAreTwoUiEvents_shouldSendAggregatedEvent +{ + MSALGlobalConfig.telemetryConfig.piiEnabled = YES; + // UI event #1 + __auto_type eventName = @"UI event"; + __auto_type event = [[MSIDTelemetryUIEvent alloc] initWithName:eventName context:self.context]; + [[MSIDTelemetry sharedInstance] startEvent:self.requestId eventName:eventName]; + [[MSIDTelemetry sharedInstance] stopEvent:self.requestId event:event]; + // UI event #2 + eventName = @"UI event 2"; + event = [[MSIDTelemetryUIEvent alloc] initWithName:eventName context:self.context]; + [event setProperty:MSID_TELEMETRY_KEY_USER_CANCEL value:@"1"]; + [event setProperty:MSID_TELEMETRY_KEY_LOGIN_HINT value:@"2"]; + [event setProperty:MSID_TELEMETRY_KEY_NTLM_HANDLED value:@"3"]; + [[MSIDTelemetry sharedInstance] startEvent:self.requestId eventName:eventName]; + [[MSIDTelemetry sharedInstance] stopEvent:self.requestId event:event]; + + [[MSIDTelemetry sharedInstance] flush:self.requestId]; + + XCTAssertNotNil(self.receivedEvent); + NSDictionary *eventInfo = self.receivedEvent; +#if TARGET_OS_IPHONE + XCTAssertEqual(eventInfo.count, 14); + XCTAssertNotNil(eventInfo[@"msal.x_client_dm"]); + XCTAssertNotNil(eventInfo[@"msal.application_version"]); +#else + XCTAssertEqual(eventInfo.count, 13); +#endif + XCTAssertEqualObjects(eventInfo[@"msal.correlation_id"], @"00000000-0000-0000-0000-000000000001"); + XCTAssertNotNil(eventInfo[@"msal.request_id"]); + XCTAssertEqualObjects(eventInfo[@"msal.ntlm"], @"3"); + XCTAssertEqualObjects(eventInfo[@"msal.ui_event_count"], @2); + XCTAssertEqualObjects(eventInfo[@"msal.user_cancel"], @"1"); + XCTAssertEqualObjects(eventInfo[@"msal.login_hint"], @"d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35"); + XCTAssertNotNil(eventInfo[@"msal.x_client_cpu"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_os"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_sku"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_ver"]); + XCTAssertNotNil(eventInfo[@"msal.application_name"]); + XCTAssertNotNil(eventInfo[@"msal.device_id"]); +} + +- (void)testFlush_whenThereIsOneBrokerEvent_shouldSendAggregatedEvent +{ + // Broker event #1 + __auto_type eventName = @"Broker event"; + __auto_type event = [[MSIDTelemetryBrokerEvent alloc] initWithName:eventName context:self.context]; + [[MSIDTelemetry sharedInstance] startEvent:self.requestId eventName:eventName]; + [[MSIDTelemetry sharedInstance] stopEvent:self.requestId event:event]; + + [[MSIDTelemetry sharedInstance] flush:self.requestId]; + + XCTAssertNotNil(self.receivedEvent); + NSDictionary *eventInfo = self.receivedEvent; +#if TARGET_OS_IPHONE + XCTAssertEqual(eventInfo.count, 8); + XCTAssertNotNil(eventInfo[@"msal.x_client_dm"]); +#else + XCTAssertEqual(eventInfo.count, 7); +#endif + XCTAssertEqualObjects(eventInfo[@"msal.correlation_id"], @"00000000-0000-0000-0000-000000000001"); + XCTAssertEqualObjects(eventInfo[@"msal.broker_app"], @"Microsoft Authenticator"); + XCTAssertNotNil(eventInfo[@"msal.request_id"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_cpu"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_os"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_sku"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_ver"]); +} + +- (void)testFlush_whenThereAreTwoBrokerEvents_shouldSendAggregatedEvent +{ + // Broker event #1 + __auto_type eventName = @"Broker event"; + __auto_type event = [[MSIDTelemetryBrokerEvent alloc] initWithName:eventName context:self.context]; + [[MSIDTelemetry sharedInstance] startEvent:self.requestId eventName:eventName]; + [[MSIDTelemetry sharedInstance] stopEvent:self.requestId event:event]; + // Broker event #2 + eventName = @"Broker event 2"; + event = [[MSIDTelemetryBrokerEvent alloc] initWithName:eventName context:self.context]; + [event setProperty:MSID_TELEMETRY_KEY_BROKER_VERSION value:@"134"]; + [[MSIDTelemetry sharedInstance] startEvent:self.requestId eventName:eventName]; + [[MSIDTelemetry sharedInstance] stopEvent:self.requestId event:event]; + + [[MSIDTelemetry sharedInstance] flush:self.requestId]; + + XCTAssertNotNil(self.receivedEvent); + NSDictionary *eventInfo = self.receivedEvent; +#if TARGET_OS_IPHONE + XCTAssertEqual(eventInfo.count, 9); + XCTAssertNotNil(eventInfo[@"msal.x_client_dm"]); +#else + XCTAssertEqual(eventInfo.count, 8); +#endif + XCTAssertEqualObjects(eventInfo[@"msal.correlation_id"], @"00000000-0000-0000-0000-000000000001"); + XCTAssertEqualObjects(eventInfo[@"msal.broker_app"], @"Microsoft Authenticator"); + XCTAssertEqualObjects(eventInfo[@"msal.broker_version"], @"134"); + XCTAssertNotNil(eventInfo[@"msal.request_id"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_cpu"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_os"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_sku"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_ver"]); +} + +- (void)testFlush_whenThereIsOneAuthorityValidationEvent_shouldSendAggregatedEvent +{ + // Authority validation event #1 + __auto_type eventName = @"Authority validation event"; + __auto_type event = [[MSIDTelemetryAuthorityValidationEvent alloc] initWithName:eventName context:self.context]; + [[MSIDTelemetry sharedInstance] startEvent:self.requestId eventName:eventName]; + [[MSIDTelemetry sharedInstance] stopEvent:self.requestId event:event]; + + [[MSIDTelemetry sharedInstance] flush:self.requestId]; + + XCTAssertNotNil(self.receivedEvent); + NSDictionary *eventInfo = self.receivedEvent; +#if TARGET_OS_IPHONE + XCTAssertEqual(eventInfo.count, 7); + XCTAssertNotNil(eventInfo[@"msal.x_client_dm"]); +#else + XCTAssertEqual(eventInfo.count, 6); +#endif + XCTAssertEqualObjects(eventInfo[@"msal.correlation_id"], @"00000000-0000-0000-0000-000000000001"); + XCTAssertNotNil(eventInfo[@"msal.request_id"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_cpu"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_os"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_sku"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_ver"]); +} + +- (void)testFlush_whenThereAreTwoAuthorityValidationEvents_shouldSendAggregatedEvent +{ + MSALGlobalConfig.telemetryConfig.piiEnabled = YES; + // Authority validation event #1 + __auto_type eventName = @"Authority validation event"; + __auto_type event = [[MSIDTelemetryAuthorityValidationEvent alloc] initWithName:eventName context:self.context]; + [[MSIDTelemetry sharedInstance] startEvent:self.requestId eventName:eventName]; + [[MSIDTelemetry sharedInstance] stopEvent:self.requestId event:event]; + // Authority validation event #2 + eventName = @"Authority validation event 2"; + event = [[MSIDTelemetryAuthorityValidationEvent alloc] initWithName:eventName context:self.context]; + [event setProperty:MSID_TELEMETRY_KEY_AUTHORITY_VALIDATION_STATUS value:@"1"]; + [event setProperty:MSID_TELEMETRY_KEY_AUTHORITY_TYPE value:@"2"]; + [event setProperty:MSID_TELEMETRY_KEY_AUTHORITY value:@"3"]; + [[MSIDTelemetry sharedInstance] startEvent:self.requestId eventName:eventName]; + [[MSIDTelemetry sharedInstance] stopEvent:self.requestId event:event]; + + [[MSIDTelemetry sharedInstance] flush:self.requestId]; + + XCTAssertNotNil(self.receivedEvent); + NSDictionary *eventInfo = self.receivedEvent; +#if TARGET_OS_IPHONE + XCTAssertEqual(eventInfo.count, 13); + XCTAssertNotNil(eventInfo[@"msal.x_client_dm"]); + XCTAssertNotNil(eventInfo[@"msal.application_version"]); +#else + XCTAssertEqual(eventInfo.count, 12); +#endif + XCTAssertEqualObjects(eventInfo[@"msal.correlation_id"], @"00000000-0000-0000-0000-000000000001"); + XCTAssertEqualObjects(eventInfo[@"msal.authority_validation_status"], @"1"); + XCTAssertEqualObjects(eventInfo[@"msal.authority_type"], @"2"); + XCTAssertEqualObjects(eventInfo[@"msal.authority"], @"3"); + XCTAssertNotNil(eventInfo[@"msal.request_id"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_cpu"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_os"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_sku"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_ver"]); + XCTAssertNotNil(eventInfo[@"msal.application_name"]); + XCTAssertNotNil(eventInfo[@"msal.device_id"]); +} + +- (void)testFlush_whenThereIsEventAndObserverRemoved_shouldNotSendEvents +{ + NSString *requestId = [[MSIDTelemetry sharedInstance] generateRequestId]; + NSString *eventName = @"test event"; + MSIDTelemetryBaseEvent *event = [[MSIDTelemetryBaseEvent alloc] initWithName:eventName context:nil]; + [event setProperty:MSID_TELEMETRY_KEY_USER_ID value:@"id1234"]; + [[MSIDTelemetry sharedInstance] startEvent:requestId eventName:eventName]; + [[MSIDTelemetry sharedInstance] stopEvent:requestId event:event]; + MSALGlobalConfig.telemetryConfig.telemetryCallback = nil; + + [[MSIDTelemetry sharedInstance] flush:requestId]; + + XCTAssertNil(self.receivedEvent); +} + +- (void)testFlush_whenThereAre2EventsAndObserverIsSetAndSetTelemetryOnFailureYes_shouldFilterEvents +{ + MSALGlobalConfig.telemetryConfig.notifyOnFailureOnly = YES; + // HTTP event + [[MSIDTelemetry sharedInstance] startEvent:self.requestId eventName:@"httpEvent"]; + MSIDTelemetryHttpEvent *httpEvent = [[MSIDTelemetryHttpEvent alloc] initWithName:@"httpEvent" context:self.context]; + [httpEvent setHttpErrorCode:@"error_code_123"]; + [[MSIDTelemetry sharedInstance] stopEvent:self.requestId event:httpEvent]; + + [[MSIDTelemetry sharedInstance] flush:self.requestId]; + + NSDictionary *eventInfo = self.receivedEvent; +#if TARGET_OS_IPHONE + XCTAssertEqual(eventInfo.count, 10); + XCTAssertNotNil(eventInfo[@"msal.x_client_dm"]); +#else + XCTAssertEqual(eventInfo.count, 9); +#endif + XCTAssertEqualObjects(eventInfo[@"msal.correlation_id"], @"00000000-0000-0000-0000-000000000001"); + XCTAssertEqualObjects(eventInfo[@"msal.http_event_count"], @1); + XCTAssertEqualObjects(eventInfo[@"msal.oauth_error_code"], @""); + XCTAssertEqualObjects(eventInfo[@"msal.response_code"], @"error_code_123"); + XCTAssertNotNil(eventInfo[@"msal.request_id"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_cpu"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_os"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_sku"]); + XCTAssertNotNil(eventInfo[@"msal.x_client_ver"]); +} + +- (void)testFlush_whenThereIs1NonErrorEventsAndObserverIsSetAndSetTelemetryOnFailureYes_shouldNotSendEvents +{ + MSALGlobalConfig.telemetryConfig.notifyOnFailureOnly = YES; + // HTTP event + [[MSIDTelemetry sharedInstance] startEvent:self.requestId eventName:@"httpEvent"]; + MSIDTelemetryHttpEvent *httpEvent = [[MSIDTelemetryHttpEvent alloc] initWithName:@"httpEvent" context:self.context]; + [[MSIDTelemetry sharedInstance] stopEvent:self.requestId event:httpEvent]; + + [[MSIDTelemetry sharedInstance] flush:self.requestId]; + + XCTAssertNil(self.receivedEvent); +} + +@end diff --git a/MSAL/test/unit/MSALTelemetryTests.m b/MSAL/test/unit/MSALTelemetryTests.m index d54faa1d56..bc0238acd3 100644 --- a/MSAL/test/unit/MSALTelemetryTests.m +++ b/MSAL/test/unit/MSALTelemetryTests.m @@ -28,21 +28,27 @@ #import "MSALTestCase.h" #import "MSALTelemetry.h" #import "MSIDTelemetry+Internal.h" -#import "MSIDTelemetryHttpEvent.h" #import "MSIDTelemetryEventStrings.h" -#import "MSALTelemetryTestDispatcher.h" +#import "MSALTestTelemetryEventsObserver.h" #import "XCTestCase+HelperMethods.h" #import "NSData+MSIDExtensions.h" +#import "MSIDTestContext.h" +#import "MSIDTelemetryHttpEvent.h" +#import "MSIDTelemetryAPIEvent.h" +#import "MSIDTelemetryCacheEvent.h" +#import "MSIDTelemetryUIEvent.h" +#import "MSIDTelemetryBrokerEvent.h" +#import "MSIDTelemetryAuthorityValidationEvent.h" #import "MSALTelemetryConfig+Internal.h" -@interface MSALTelemetryTests : MSALTestCase +@interface MSALTelemetryDefaultTests : MSALTestCase @property (nonatomic) NSArray *> *receivedEvents; -@property (nonatomic) MSALTelemetryTestDispatcher *dispatcher; +@property (nonatomic) MSALTestTelemetryEventsObserver *observer; @end -@implementation MSALTelemetryTests +@implementation MSALTelemetryDefaultTests - (void)setUp { @@ -55,7 +61,7 @@ - (void)setUp __weak MSALTelemetryTests *weakSelf = self; [self.dispatcher setDispatcherCallback:^(NSArray *> *event) { - weakSelf.receivedEvents = event; + weakSelf.receivedEvents = events; }]; MSALTelemetryConfig.sharedInstance.piiEnabled = NO; @@ -65,12 +71,17 @@ - (void)tearDown { [super tearDown]; - self.dispatcher = nil; + self.observer = nil; + [MSALTelemetry sharedInstance].piiEnabled = NO; + [[MSALTelemetry sharedInstance] removeAllObservers]; + self.receivedEvents = nil; MSALTelemetryConfig.sharedInstance.piiEnabled = NO; } -- (void)test_telemetryPiiRules_whenPiiEnabledNo_shouldDeletePiiFields +#pragma mark - Telemetry Pii Rules + +- (void)testTelemetryPiiRules_whenPiiEnabledNo_shouldDeletePiiFields { MSALTelemetryConfig.sharedInstance.piiEnabled = NO; NSString *requestId = [[MSIDTelemetry sharedInstance] generateRequestId]; @@ -84,10 +95,10 @@ - (void)test_telemetryPiiRules_whenPiiEnabledNo_shouldDeletePiiFields NSDictionary *dictionary = [self getEventPropertiesByEventName:eventName]; XCTAssertNotNil(dictionary); - XCTAssertNil([dictionary objectForKey:MSID_TELEMETRY_KEY_USER_ID]); + XCTAssertNil(dictionary[MSID_TELEMETRY_KEY_USER_ID]); } -- (void)test_telemetryPiiRules_whenPiiEnabledYes_shouldHashPiiFields +- (void)testTelemetryPiiRules_whenPiiEnabledYes_shouldHashPiiFields { MSALTelemetryConfig.sharedInstance.piiEnabled = YES; NSString *requestId = [[MSIDTelemetry sharedInstance] generateRequestId]; @@ -101,18 +112,133 @@ - (void)test_telemetryPiiRules_whenPiiEnabledYes_shouldHashPiiFields NSDictionary *dictionary = [self getEventPropertiesByEventName:eventName]; XCTAssertNotNil(dictionary); - NSString *x = [@"id1234" dataUsingEncoding:NSUTF8StringEncoding].msidSHA256.msidHexString; - MSALAssertStringEquals([dictionary objectForKey:TELEMETRY_KEY(MSID_TELEMETRY_KEY_USER_ID)], x); + MSALAssertStringEquals(dictionary[TELEMETRY_KEY(MSID_TELEMETRY_KEY_USER_ID)], x); +} + +#pragma mark - flush + +- (void)testFlush_whenThereIsEventAndObserverIsSet_shouldSendEvents +{ + NSString *requestId = [[MSIDTelemetry sharedInstance] generateRequestId]; + NSString *eventName = @"test event"; + MSIDTelemetryBaseEvent *event = [[MSIDTelemetryBaseEvent alloc] initWithName:eventName context:nil]; + [event setProperty:MSID_TELEMETRY_KEY_USER_ID value:@"id1234"]; + [[MSIDTelemetry sharedInstance] startEvent:requestId eventName:eventName]; + [[MSIDTelemetry sharedInstance] stopEvent:requestId event:event]; + + [[MSIDTelemetry sharedInstance] flush:requestId]; + + NSDictionary *dictionary = [self getEventPropertiesByEventName:eventName]; + XCTAssertNotNil(dictionary); + XCTAssertNil([dictionary objectForKey:MSID_TELEMETRY_KEY_USER_ID]); +} + +- (void)testFlush_whenThereIsEventAndObserverRemoved_shouldNotSendEvents +{ + NSString *requestId = [[MSIDTelemetry sharedInstance] generateRequestId]; + NSString *eventName = @"test event"; + MSIDTelemetryBaseEvent *event = [[MSIDTelemetryBaseEvent alloc] initWithName:eventName context:nil]; + [event setProperty:MSID_TELEMETRY_KEY_USER_ID value:@"id1234"]; + [[MSIDTelemetry sharedInstance] startEvent:requestId eventName:eventName]; + [[MSIDTelemetry sharedInstance] stopEvent:requestId event:event]; + [[MSALTelemetry sharedInstance] removeObserver:self.observer]; + + [[MSIDTelemetry sharedInstance] flush:requestId]; + + XCTAssertNil(self.receivedEvents); +} + +- (void)testFlush_whenThereIsNoEventAndObserverIsSet_shouldNotSendEvents +{ + NSString *requestId = [[MSIDTelemetry sharedInstance] generateRequestId]; + + // Flush without adding any additional events + [[MSIDTelemetry sharedInstance] flush:requestId]; + + XCTAssertNil(self.receivedEvents); +} + +- (void)testFlush_whenThereAre2EventsAndObserverIsSet_shouldSendEvents +{ + [MSALTelemetry sharedInstance].piiEnabled = YES; + NSString *requestId = [[MSIDTelemetry sharedInstance] generateRequestId]; + NSUUID *correlationId = [NSUUID UUID]; + __auto_type context = [MSIDTestContext new]; + context.telemetryRequestId = requestId; + context.correlationId = correlationId; + // API event + [[MSIDTelemetry sharedInstance] startEvent:requestId eventName:@"apiEvent"]; + MSIDTelemetryAPIEvent *apiEvent = [[MSIDTelemetryAPIEvent alloc] initWithName:@"apiEvent" context:context]; + [apiEvent setProperty:@"api_property" value:@"api_value"]; + [apiEvent setCorrelationId:correlationId]; + [[MSIDTelemetry sharedInstance] stopEvent:requestId event:apiEvent]; + // HTTP event + [[MSIDTelemetry sharedInstance] startEvent:requestId eventName:@"httpEvent"]; + [[MSIDTelemetry sharedInstance] stopEvent:requestId + event:[[MSIDTelemetryHttpEvent alloc] initWithName:@"httpEvent" context:context]]; + + [[MSIDTelemetry sharedInstance] flush:requestId]; + + // Verify results: there should be 3 events (default, API, HTTP) + XCTAssertEqual([self.receivedEvents count], 3); + [self assertDefaultEvent:self.receivedEvents[0] piiEnabled:YES]; + [self assertAPIEvent:self.receivedEvents[1]]; + [self assertHTTPEvent:self.receivedEvents[2]]; +} + +- (void)testFlush_whenThereAre2EventsAndObserverIsSetAndSetTelemetryOnFailureYes_shouldFilterEvents +{ + [[MSALTelemetry sharedInstance] removeAllObservers]; + [[MSALTelemetry sharedInstance] addEventsObserver:self.observer setTelemetryOnFailure:YES aggregationRequired:NO]; + NSString *requestId = [[MSIDTelemetry sharedInstance] generateRequestId]; + NSUUID *correlationId = [NSUUID UUID]; + __auto_type context = [MSIDTestContext new]; + context.telemetryRequestId = requestId; + context.correlationId = correlationId; + // HTTP event + [[MSIDTelemetry sharedInstance] startEvent:requestId eventName:@"httpEvent"]; + MSIDTelemetryHttpEvent *httpEvent = [[MSIDTelemetryHttpEvent alloc] initWithName:@"httpEvent" context:context]; + [httpEvent setHttpErrorCode:@"error_code_123"]; + [[MSIDTelemetry sharedInstance] stopEvent:requestId event:httpEvent]; + + [[MSIDTelemetry sharedInstance] flush:requestId]; + + XCTAssertEqual([self.receivedEvents count], 2); + [self assertDefaultEvent:self.receivedEvents[0] piiEnabled:NO]; + [self assertHTTPEvent:self.receivedEvents[1]]; + NSString *errorCode = self.receivedEvents[1][TELEMETRY_KEY(MSID_TELEMETRY_KEY_HTTP_RESPONSE_CODE)]; + XCTAssertNotNil(errorCode); + XCTAssertEqualObjects(errorCode, @"error_code_123"); +} +- (void)testFlush_whenThereIs1NonErrorEventsAndObserverIsSetAndSetTelemetryOnFailureYes_shouldNotSendEvents +{ + [[MSALTelemetry sharedInstance] removeAllObservers]; + [[MSALTelemetry sharedInstance] addEventsObserver:self.observer setTelemetryOnFailure:YES aggregationRequired:NO]; + NSString *requestId = [[MSIDTelemetry sharedInstance] generateRequestId]; + NSUUID* correlationId = [NSUUID UUID]; + __auto_type context = [MSIDTestContext new]; + context.telemetryRequestId = requestId; + context.correlationId = correlationId; + // HTTP event + [[MSIDTelemetry sharedInstance] startEvent:requestId eventName:@"httpEvent"]; + MSIDTelemetryHttpEvent *httpEvent = [[MSIDTelemetryHttpEvent alloc] initWithName:@"httpEvent" context:context]; + [[MSIDTelemetry sharedInstance] stopEvent:requestId event:httpEvent]; + + [[MSIDTelemetry sharedInstance] flush:requestId]; + + XCTAssertNil(self.receivedEvents); } #pragma mark - Private - (NSDictionary *)getEventPropertiesByEventName:(NSString *)eventName { - for (NSDictionary *eventInfo in self.receivedEvents) { - if ([[eventInfo objectForKey:TELEMETRY_KEY(MSID_TELEMETRY_KEY_EVENT_NAME)] isEqualToString:eventName]) { + for (NSDictionary *eventInfo in self.receivedEvents) + { + if ([[eventInfo objectForKey:TELEMETRY_KEY(MSID_TELEMETRY_KEY_EVENT_NAME)] isEqualToString:eventName]) + { return eventInfo; } } @@ -120,4 +246,45 @@ - (NSDictionary *)getEventPropertiesByEventName:(NSString *)eventName return nil; } +- (void)assertDefaultEvent:(NSDictionary *)eventInfo piiEnabled:(BOOL)piiEnabled +{ + __auto_type defaultEventPropertyNames = [[NSSet alloc] initWithArray:[eventInfo allKeys]]; + XCTAssertEqual([defaultEventPropertyNames count], piiEnabled ? 9 : 6); + XCTAssertTrue([defaultEventPropertyNames containsObject:@"msal.event_name"]); + XCTAssertTrue([defaultEventPropertyNames containsObject:@"msal.x_client_cpu"]); + XCTAssertTrue([defaultEventPropertyNames containsObject:@"msal.x_client_dm"]); + XCTAssertTrue([defaultEventPropertyNames containsObject:@"msal.x_client_os"]); + XCTAssertTrue([defaultEventPropertyNames containsObject:@"msal.x_client_sku"]); + XCTAssertTrue([defaultEventPropertyNames containsObject:@"msal.x_client_ver"]); + XCTAssertEqualObjects(eventInfo[@"msal.event_name"], @"default_event"); + + if (!piiEnabled) return; + XCTAssertTrue([defaultEventPropertyNames containsObject:@"msal.application_name"]); + XCTAssertTrue([defaultEventPropertyNames containsObject:@"msal.application_version"]); + XCTAssertTrue([defaultEventPropertyNames containsObject:@"msal.device_id"]); +} + +- (void)assertAPIEvent:(NSDictionary *)eventInfo +{ + __auto_type apiEventPropertyNames = [[NSSet alloc] initWithArray:[eventInfo allKeys]]; + XCTAssertTrue([apiEventPropertyNames containsObject:@"msal.start_time"]); + XCTAssertTrue([apiEventPropertyNames containsObject:@"msal.stop_time"]); + XCTAssertTrue([apiEventPropertyNames containsObject:@"msal.correlation_id"]); + XCTAssertTrue([apiEventPropertyNames containsObject:@"msal.response_time"]); + XCTAssertTrue([apiEventPropertyNames containsObject:@"msal.request_id"]); + XCTAssertEqualObjects(eventInfo[@"msal.event_name"], @"apiEvent"); + XCTAssertEqualObjects(eventInfo[@"msal.api_property"], @"api_value"); +} + +- (void)assertHTTPEvent:(NSDictionary *)eventInfo +{ + __auto_type httpEventPropertyNames = [[NSSet alloc] initWithArray:[eventInfo allKeys]]; + XCTAssertTrue([httpEventPropertyNames containsObject:@"msal.start_time"]); + XCTAssertTrue([httpEventPropertyNames containsObject:@"msal.stop_time"]); + XCTAssertTrue([httpEventPropertyNames containsObject:@"msal.response_time"]); + XCTAssertEqualObjects(eventInfo[@"msal.event_name"], @"httpEvent"); +} + @end + + diff --git a/MSAL/test/unit/MSALUserTests.m b/MSAL/test/unit/MSALUserTests.m deleted file mode 100644 index a66e8f5877..0000000000 --- a/MSAL/test/unit/MSALUserTests.m +++ /dev/null @@ -1,119 +0,0 @@ -//------------------------------------------------------------------------------ -// -// 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 "MSALTestCase.h" -#import "MSIDClientInfo.h" -#import "MSIDAADV2IdTokenClaims.h" -#import "MSALAccount+Internal.h" -#import "MSIDAccount.h" -#import "MSALAccountId.h" -#import "MSIDAADAuthority.h" -#import "MSIDAccountIdentifier.h" -#import "MSIDAuthority+Internal.h" - -@interface MSALUserTests : MSALTestCase - -@end - -@implementation MSALUserTests - -- (void)setUp { - [super setUp]; - // Put setup code here. This method is called before the invocation of each test method in the class. -} - -- (void)tearDown { - // Put teardown code here. This method is called after the invocation of each test method in the class. - [super tearDown]; -} - -- (void)testInitWithMSIDAccount_whenValidAccount_shouldInit -{ - MSIDAccount *msidAccount = [MSIDAccount new]; - msidAccount.accountIdentifier = [[MSIDAccountIdentifier alloc] initWithDisplayableId:@"user@contoso.com" homeAccountId:@"uid.utid"]; - msidAccount.username = @"user@contoso.com"; - msidAccount.name = @"User"; - msidAccount.localAccountId = @"localoid"; - __auto_type authorityUrl = [NSURL URLWithString:@"https://login.microsoftonline.com/tid"]; - __auto_type authority = [[MSIDAADAuthority alloc] initWithURL:authorityUrl context:nil error:nil]; - msidAccount.authority = authority; - NSDictionary *clientInfoClaims = @{ @"uid" : @"uid", - @"utid" : @"utid" - }; - - - MSIDClientInfo *clientInfo = [[MSIDClientInfo alloc] initWithJSONDictionary:clientInfoClaims error:nil]; - msidAccount.clientInfo = clientInfo; - - MSALAccount *account = [[MSALAccount alloc] initWithMSIDAccount:msidAccount]; - - XCTAssertNotNil(account); - XCTAssertEqualObjects(account.homeAccountId.objectId, @"uid"); - XCTAssertEqualObjects(account.homeAccountId.tenantId, @"utid"); - XCTAssertEqualObjects(account.name, @"User"); - XCTAssertEqualObjects(account.username, @"user@contoso.com"); -} - -- (void)testCopy_whenValidAccount_shouldCopy -{ - MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"displayableID" - name:@"name" - homeAccountId:@"1.2" - localAccountId:@"2.3" - environment:@"login.microsoftonline.com" - tenantId:@"3"]; - XCTAssertNotNil(account); - - MSALAccount *account2 = [account copy]; - - XCTAssertNotNil(account2); - // The two objects should have different pointers - XCTAssertNotEqual(account, account2); - - XCTAssertEqualObjects(account.homeAccountId.objectId, account2.homeAccountId.objectId); - XCTAssertEqualObjects(account.homeAccountId.tenantId, account2.homeAccountId.tenantId); - XCTAssertEqualObjects(account.username, account2.username); - XCTAssertEqualObjects(account.name, account2.name); -} - -- (void)testEquals_whenEqual_shouldReturnTrue -{ - MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"displayableID" - name:@"name" - homeAccountId:@"1.2" - localAccountId:@"2.3" - environment:@"login.microsoftonline.com" - tenantId:@"3"]; - - XCTAssertNotNil(account); - MSALAccount *account2 = [account copy]; - - XCTAssertNotNil(account2); - XCTAssertEqualObjects(account, account2); -} - -@end diff --git a/MSAL/test/unit/ios/external-cache/MSALLegacySharedADALAccountTests.m b/MSAL/test/unit/ios/external-cache/MSALLegacySharedADALAccountTests.m new file mode 100644 index 0000000000..45f6a80382 --- /dev/null +++ b/MSAL/test/unit/ios/external-cache/MSALLegacySharedADALAccountTests.m @@ -0,0 +1,402 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALAccount+Internal.h" +#import "MSALAccountId+Internal.h" +#import "MSALLegacySharedADALAccount.h" +#import "MSALAccountEnumerationParameters.h" +#import "MSALLegacySharedAccountTestUtil.h" + +@interface MSALLegacySharedADALAccountTests : XCTestCase + +@end + +@implementation MSALLegacySharedADALAccountTests + +#pragma mark - Init + +- (void)testInitWithJSONDictionary_whenWrongAccountType_shouldReturnNilAndError +{ + NSMutableDictionary *jsonDictionary = [[MSALLegacySharedAccountTestUtil sampleADALJSONDictionary] mutableCopy]; + jsonDictionary[@"type"] = @"UnknownType"; + + NSError *error = nil; + MSALLegacySharedADALAccount *account = [[MSALLegacySharedADALAccount alloc] initWithJSONDictionary:jsonDictionary error:&error]; + XCTAssertNil(account); + XCTAssertNotNil(error); + XCTAssertEqual(error.code, MSIDErrorInternal); + XCTAssertEqualObjects(error.domain, MSIDErrorDomain); + XCTAssertEqualObjects(error.userInfo[MSIDErrorDescriptionKey], @"Unexpected account type"); +} + +- (void)testInitWithJSONDictionary_whenNilAuthEndpoint_shouldReturnNilAndFillError +{ + NSMutableDictionary *jsonDictionary = [[MSALLegacySharedAccountTestUtil sampleADALJSONDictionary] mutableCopy]; + jsonDictionary[@"authEndpointUrl"] = nil; + + NSError *error = nil; + MSALLegacySharedADALAccount *account = [[MSALLegacySharedADALAccount alloc] initWithJSONDictionary:jsonDictionary error:&error]; + XCTAssertNil(account); + XCTAssertNotNil(error); + XCTAssertEqual(error.code, MSIDErrorInternal); + XCTAssertEqualObjects(error.domain, MSIDErrorDomain); + XCTAssertEqualObjects(error.userInfo[MSIDErrorDescriptionKey], @"Unexpected authority found"); +} + +- (void)testInitWithJSONDictionary_whenWrongAuthEndpoint_shouldReturnNilAndFillError +{ + NSMutableDictionary *jsonDictionary = [[MSALLegacySharedAccountTestUtil sampleADALJSONDictionary] mutableCopy]; + jsonDictionary[@"authEndpointUrl"] = @"https://b2clogin.microsoft.com/"; + + NSError *error = nil; + MSALLegacySharedADALAccount *account = [[MSALLegacySharedADALAccount alloc] initWithJSONDictionary:jsonDictionary error:&error]; + XCTAssertNil(account); + XCTAssertNotNil(error); + XCTAssertEqual(error.code, MSIDErrorInternal); + XCTAssertEqualObjects(error.domain, MSIDErrorDomain); + XCTAssertEqualObjects(error.userInfo[MSIDErrorDescriptionKey], @"authority must have AAD tenant."); +} + +- (void)testInitWithJSONDictionary_whenAllInformationPresentAndHomeTenant_shouldCreateAccount +{ + NSString *accountId = [NSUUID UUID].UUIDString.lowercaseString; + NSString *objectId = [NSUUID UUID].UUIDString.lowercaseString; + NSString *tenantId = [NSUUID UUID].UUIDString.lowercaseString; + + NSDictionary *adalAccountDictionary = [MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:accountId objectId:objectId tenantId:tenantId username:nil]; + + NSError *error = nil; + MSALLegacySharedADALAccount *account = [[MSALLegacySharedADALAccount alloc] initWithJSONDictionary:adalAccountDictionary error:&error]; + XCTAssertNotNil(account); + XCTAssertNil(error); + XCTAssertEqualObjects(account.accountType, @"ADAL"); + XCTAssertEqualObjects(account.environment, @"login.windows.net"); + NSString *expectedIdentifier = [NSString stringWithFormat:@"%@.%@", objectId, tenantId]; + XCTAssertEqualObjects(account.identifier, expectedIdentifier); + XCTAssertEqualObjects(account.accountIdentifier, accountId); + XCTAssertEqualObjects(account.username, @"user@contoso.com"); + XCTAssertEqualObjects(account.accountClaims[@"oid"], objectId); + XCTAssertEqualObjects(account.accountClaims[@"tid"], tenantId); + XCTAssertEqualObjects(account.accountClaims[@"name"], @"myDisplayName.contoso.user"); +} + +- (void)testInitWithJSONDictionary_whenAllInformationPresentAndGuestTenant_shouldCreateAccountWithoutIdentifier +{ + NSString *accountId = [NSUUID UUID].UUIDString.lowercaseString; + NSString *objectId = [NSUUID UUID].UUIDString.lowercaseString; + NSString *tenantId = [NSUUID UUID].UUIDString.lowercaseString; + + NSDictionary *adalAccountDictionary = [MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:accountId objectId:objectId tenantId:tenantId username:nil]; + + NSMutableDictionary *mutableDict = [adalAccountDictionary mutableCopy]; + mutableDict[@"authEndpointUrl"] = @"https://login.microsoftonline.com/contoso.com"; + + NSError *error = nil; + MSALLegacySharedADALAccount *account = [[MSALLegacySharedADALAccount alloc] initWithJSONDictionary:mutableDict error:&error]; + XCTAssertNotNil(account); + XCTAssertNil(error); + XCTAssertEqualObjects(account.accountType, @"ADAL"); + XCTAssertEqualObjects(account.environment, @"login.microsoftonline.com"); + XCTAssertNil(account.identifier); + XCTAssertEqualObjects(account.accountIdentifier, accountId); + XCTAssertEqualObjects(account.username, @"user@contoso.com"); + XCTAssertEqualObjects(account.accountClaims[@"oid"], objectId); + XCTAssertEqualObjects(account.accountClaims[@"tid"], tenantId); + XCTAssertEqualObjects(account.accountClaims[@"name"], @"myDisplayName.contoso.user"); +} + +#pragma mark - InitWithMSALAccount + +- (void)testInitWithMSALAccount_whenV1Version_shouldReturnNilResultAndNilError +{ + NSError *error = nil; + MSALLegacySharedADALAccount *account = [[MSALLegacySharedADALAccount alloc] initWithMSALAccount:[MSALLegacySharedAccountTestUtil testADALAccount] + accountClaims:@{} + applicationName:@"MyApp" + accountVersion:MSALLegacySharedAccountVersionV1 + error:&error]; + XCTAssertNil(account); + XCTAssertNil(error); +} + +- (void)testInitWithMSALAccount_whenNilAccount_shouldReturnNilAndFillError +{ + NSError *error = nil; + MSALAccount *msalAccount = nil; + MSALLegacySharedADALAccount *account = [[MSALLegacySharedADALAccount alloc] initWithMSALAccount:msalAccount + accountClaims:@{} + applicationName:@"MyApp" + accountVersion:MSALLegacySharedAccountVersionV3 + error:&error]; + XCTAssertNil(account); + XCTAssertNotNil(error); + XCTAssertEqual(error.code, MSIDErrorInternal); + XCTAssertEqualObjects(error.userInfo[MSIDErrorDescriptionKey], @"Unexpected parameter - no account"); +} + +- (void)testInitWithMSALAccount_whenADALAccount_andV3Version_shouldFillAllEntries +{ + NSError *error = nil; + MSALAccount *msalAccount = [MSALLegacySharedAccountTestUtil testADALAccount]; + NSDictionary *claims = @{@"name": @"Contoso User", + @"oid": @"uid", + @"tid": @"utid" + }; + MSALLegacySharedADALAccount *account = [[MSALLegacySharedADALAccount alloc] initWithMSALAccount:msalAccount + accountClaims:claims + applicationName:@"MyApp" + accountVersion:MSALLegacySharedAccountVersionV3 + error:&error]; + XCTAssertNotNil(account); + XCTAssertNil(error); + NSDictionary *resultDictionary = [account jsonDictionary]; + XCTAssertNotNil(resultDictionary[@"id"]); + XCTAssertEqualObjects(resultDictionary[@"environment"], @"PROD"); + NSString *appIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + XCTAssertEqualObjects(resultDictionary[@"originAppId"], appIdentifier); + NSString *signinStatus = resultDictionary[@"signInStatus"][appIdentifier]; + XCTAssertEqualObjects(signinStatus, @"SignedIn"); + XCTAssertEqualObjects(resultDictionary[@"username"], @"user@contoso.com"); + XCTAssertEqualObjects(resultDictionary[@"additionalProperties"][@"createdBy"], @"MyApp"); + XCTAssertEqualObjects(resultDictionary[@"displayName"], @"Contoso User"); + XCTAssertEqualObjects(resultDictionary[@"oid"], @"uid"); + XCTAssertEqualObjects(resultDictionary[@"tenantId"], @"utid"); + XCTAssertEqualObjects(resultDictionary[@"type"], @"ADAL"); + XCTAssertEqualObjects(resultDictionary[@"authEndpointUrl"], @"https://login.microsoftonline.com/common"); + +} + +- (void)testInitWithMSALAccount_whenADALAccount_andV2Version_shouldFillAllEntriesExceptOriginApp +{ + NSError *error = nil; + MSALAccount *msalAccount = [MSALLegacySharedAccountTestUtil testADALAccount]; + NSDictionary *claims = @{@"name": @"Contoso User", + @"oid": @"uid", + @"tid": @"utid" + }; + MSALLegacySharedADALAccount *account = [[MSALLegacySharedADALAccount alloc] initWithMSALAccount:msalAccount + accountClaims:claims + applicationName:@"MyApp" + accountVersion:MSALLegacySharedAccountVersionV2 + error:&error]; + XCTAssertNotNil(account); + XCTAssertNil(error); + NSDictionary *resultDictionary = [account jsonDictionary]; + XCTAssertNotNil(resultDictionary[@"id"]); + XCTAssertEqualObjects(resultDictionary[@"environment"], @"PROD"); + NSString *appIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + XCTAssertNil(resultDictionary[@"originAppId"]); + NSString *signinStatus = resultDictionary[@"signInStatus"][appIdentifier]; + XCTAssertEqualObjects(signinStatus, @"SignedIn"); + XCTAssertEqualObjects(resultDictionary[@"username"], @"user@contoso.com"); + XCTAssertEqualObjects(resultDictionary[@"additionalProperties"][@"createdBy"], @"MyApp"); + XCTAssertEqualObjects(resultDictionary[@"displayName"], @"Contoso User"); + XCTAssertEqualObjects(resultDictionary[@"oid"], @"uid"); + XCTAssertEqualObjects(resultDictionary[@"tenantId"], @"utid"); + XCTAssertEqualObjects(resultDictionary[@"type"], @"ADAL"); + XCTAssertEqualObjects(resultDictionary[@"authEndpointUrl"], @"https://login.microsoftonline.com/common"); +} + +- (void)testInitWithMSALAccount_whenADALAccount_andGuestTenant_shouldFillAllEntriesWithGuestTenantAuthority +{ + NSError *error = nil; + MSALAccount *msalAccount = [MSALLegacySharedAccountTestUtil testADALAccount]; + NSDictionary *claims = @{@"name": @"Contoso User", + @"oid": @"guest_uid", + @"tid": @"guest_utid" + }; + MSALLegacySharedADALAccount *account = [[MSALLegacySharedADALAccount alloc] initWithMSALAccount:msalAccount + accountClaims:claims + applicationName:@"MyApp" + accountVersion:MSALLegacySharedAccountVersionV3 + error:&error]; + XCTAssertNotNil(account); + XCTAssertNil(error); + NSDictionary *resultDictionary = [account jsonDictionary]; + XCTAssertNotNil(resultDictionary[@"id"]); + XCTAssertEqualObjects(resultDictionary[@"environment"], @"PROD"); + NSString *appIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + XCTAssertEqualObjects(resultDictionary[@"originAppId"], appIdentifier); + NSString *signinStatus = resultDictionary[@"signInStatus"][appIdentifier]; + XCTAssertEqualObjects(signinStatus, @"SignedIn"); + XCTAssertEqualObjects(resultDictionary[@"username"], @"user@contoso.com"); + XCTAssertEqualObjects(resultDictionary[@"additionalProperties"][@"createdBy"], @"MyApp"); + XCTAssertEqualObjects(resultDictionary[@"displayName"], @"Contoso User"); + XCTAssertEqualObjects(resultDictionary[@"oid"], @"guest_uid"); + XCTAssertEqualObjects(resultDictionary[@"tenantId"], @"guest_utid"); + XCTAssertEqualObjects(resultDictionary[@"type"], @"ADAL"); + XCTAssertEqualObjects(resultDictionary[@"authEndpointUrl"], @"https://login.microsoftonline.com/guest_utid"); +} + +#pragma mark - MatchesParameters + +- (void)testMatchesWithParameters_whenShouldHaveAssociatedRefreshTokenYES_AndAccountSignedOut_shouldReturnNO +{ + NSMutableDictionary *jsonDictionary = [[MSALLegacySharedAccountTestUtil sampleADALJSONDictionary] mutableCopy]; + + NSDictionary *signinStatusDict = @{[[NSBundle mainBundle] bundleIdentifier]: @"SignedOut"}; + jsonDictionary[@"signInStatus"] = signinStatusDict; + + MSALLegacySharedADALAccount *account = [[MSALLegacySharedADALAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + MSALAccountEnumerationParameters *params = [MSALAccountEnumerationParameters new]; + params.returnOnlySignedInAccounts = YES; + BOOL result = [account matchesParameters:params]; + XCTAssertFalse(result); +} + +- (void)testMatchesWithParameters_whenNilParameters_shouldReturnYES +{ + NSDictionary *jsonDictionary = [MSALLegacySharedAccountTestUtil sampleADALJSONDictionary]; + MSALLegacySharedADALAccount *account = [[MSALLegacySharedADALAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + MSALAccountEnumerationParameters *params = nil; + BOOL result = [account matchesParameters:params]; + XCTAssertTrue(result); +} + +- (void)testMatchesWithParameters_whenIdentifierNonNil_andMatchingIdentifier_shouldReturnYES +{ + NSDictionary *jsonDictionary = [MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:@"accountId" objectId:@"oid" tenantId:@"utid" username:nil]; + + MSALLegacySharedADALAccount *account = [[MSALLegacySharedADALAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + MSALAccountEnumerationParameters *params = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:@"oid.utid"]; + params.returnOnlySignedInAccounts = NO; + BOOL result = [account matchesParameters:params]; + XCTAssertTrue(result); +} + +- (void)testMatchesWithParameters_whenIdentifierAndUsernameSet_andMatchingAllOptions_shouldReturnYES +{ + NSDictionary *jsonDictionary = [MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:@"accountId" objectId:@"oid" tenantId:@"utid" username:nil]; + + MSALLegacySharedADALAccount *account = [[MSALLegacySharedADALAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + MSALAccountEnumerationParameters *params = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:@"oid.utid" username:@"user@contoso.com"]; + params.returnOnlySignedInAccounts = NO; + BOOL result = [account matchesParameters:params]; + XCTAssertTrue(result); +} + +- (void)testMatchesWithParameters_whenAllMatchignOptionsSet_andMatchingAllOptions_butDifferentCase_shouldReturnYES +{ + NSMutableDictionary *jsonDictionary = [[MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:@"accountId" objectId:@"oid" tenantId:@"utid" username:nil] mutableCopy]; + NSDictionary *signinStatusDict = @{[[NSBundle mainBundle] bundleIdentifier]: @"SignedIn"}; + jsonDictionary[@"signInStatus"] = signinStatusDict; + + MSALLegacySharedADALAccount *account = [[MSALLegacySharedADALAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + MSALAccountEnumerationParameters *params = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:@"oID.UTid" username:@"USER@contoso.COM"]; + params.returnOnlySignedInAccounts = YES; + BOOL result = [account matchesParameters:params]; + XCTAssertTrue(result); +} + +- (void)testMatchesWithParameters_whenTenantProfileIdentifierNonNil_andTenantProfileIdentifierSame_shouldReturnYES +{ + NSDictionary *jsonDictionary = [MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:@"accountId" objectId:@"myoid" tenantId:@"utid" username:nil]; + + MSALLegacySharedADALAccount *account = [[MSALLegacySharedADALAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + MSALAccountEnumerationParameters *params = [[MSALAccountEnumerationParameters alloc] initWithTenantProfileIdentifier:@"myoid"]; + params.returnOnlySignedInAccounts = NO; + BOOL result = [account matchesParameters:params]; + XCTAssertTrue(result); +} + +- (void)testMatchesWithParamaters_whenUsernameNonNil_andUsernameDifferent_shouldReturnNO +{ + NSDictionary *jsonDictionary = [MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:@"accountId" objectId:@"myoid" tenantId:@"utid" username:nil]; + + MSALLegacySharedADALAccount *account = [[MSALLegacySharedADALAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + MSALAccountEnumerationParameters *params = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:nil username:@"user2@contoso.com"]; + params.returnOnlySignedInAccounts = NO; + BOOL result = [account matchesParameters:params]; + XCTAssertFalse(result); +} + +- (void)testMatchesWithParameters_whenTenantProfileIdentifierNonNil_andTenantProfileIdentifierDifferent_shouldReturnNO +{ + NSDictionary *jsonDictionary = [MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:@"accountId" objectId:@"myoid" tenantId:@"utid" username:nil]; + + MSALLegacySharedADALAccount *account = [[MSALLegacySharedADALAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + MSALAccountEnumerationParameters *params = [[MSALAccountEnumerationParameters alloc] initWithTenantProfileIdentifier:@"myoid2"]; + params.returnOnlySignedInAccounts = NO; + BOOL result = [account matchesParameters:params]; + XCTAssertFalse(result); +} + +- (void)testMatchesWithParameters_whenIdentifierNonNil_andIdentifierDifferent_shouldReturnNO +{ + NSDictionary *jsonDictionary = [MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:@"accountId" objectId:@"oid" tenantId:@"utid" username:nil]; + + MSALLegacySharedADALAccount *account = [[MSALLegacySharedADALAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + MSALAccountEnumerationParameters *params = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:@"oid.utid2"]; + params.returnOnlySignedInAccounts = NO; + BOOL result = [account matchesParameters:params]; + XCTAssertFalse(result); +} + +#pragma mark - Update + +- (void)testUpdateWithMSALAccount_whenUsernameAndSigninStatusChanged_shouldUpdateUsername +{ + NSString *appIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + NSMutableDictionary *jsonDictionary = [[MSALLegacySharedAccountTestUtil sampleADALJSONDictionary] mutableCopy]; + NSDictionary *signinStatusDict = @{appIdentifier : @"SignedOut"}; + jsonDictionary[@"signInStatus"] = signinStatusDict; + jsonDictionary[@"username"] = @"old@contoso.old.com"; + + MSALLegacySharedADALAccount *account = [[MSALLegacySharedADALAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + NSError *updateError = nil; + BOOL result = [account updateAccountWithMSALAccount:[MSALLegacySharedAccountTestUtil testADALAccount] + applicationName:@"MyApp" + operation:MSALLegacySharedAccountUpdateOperation + accountVersion:MSALLegacySharedAccountVersionV3 + error:&updateError]; + + XCTAssertTrue(result); + XCTAssertNil(updateError); + XCTAssertNotEqualObjects([account jsonDictionary], jsonDictionary); + NSString *newSigninStatus = [account jsonDictionary][@"signInStatus"][appIdentifier]; + XCTAssertEqualObjects(newSigninStatus, @"SignedIn"); + NSString *updatedByStatus = [account jsonDictionary][@"additionalProperties"][@"updatedBy"]; + XCTAssertEqualObjects(updatedByStatus, @"MyApp"); + NSString *updatedAt = [account jsonDictionary][@"additionalProperties"][@"updatedAt"]; + XCTAssertNotNil(updatedAt); + XCTAssertEqualObjects(account.accountType, @"ADAL"); + XCTAssertEqualObjects(account.username, @"user@contoso.com"); + +} + +@end diff --git a/MSAL/test/unit/ios/external-cache/MSALLegacySharedAccountFactoryTests.m b/MSAL/test/unit/ios/external-cache/MSALLegacySharedAccountFactoryTests.m new file mode 100644 index 0000000000..f5c4d24719 --- /dev/null +++ b/MSAL/test/unit/ios/external-cache/MSALLegacySharedAccountFactoryTests.m @@ -0,0 +1,100 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALLegacySharedAccountFactory.h" +#import "MSALLegacySharedADALAccount.h" +#import "MSALLegacySharedMSAAccount.h" + +@interface MSALLegacySharedAccountFactoryTests : XCTestCase + +@end + +@implementation MSALLegacySharedAccountFactoryTests + +#pragma mark - accountWithJSONDictionary + +- (void)testAccountWithJSONDictionary_whenTypeMissing_shouldReturnNilFillError +{ + NSDictionary *jsonDictionary = [self sampleJSONDictionaryWithAccountType:nil]; + + NSError *error = nil; + MSALLegacySharedAccount *account = [MSALLegacySharedAccountFactory accountWithJSONDictionary:jsonDictionary error:&error]; + XCTAssertNil(account); + XCTAssertNotNil(error); +} + +- (void)testAccountWithJSONDictionary_whenTypeUnknown_shouldReturnNilAndFillError +{ + NSDictionary *jsonDictionary = [self sampleJSONDictionaryWithAccountType:@"UnknownType"]; + + NSError *error = nil; + MSALLegacySharedAccount *account = [MSALLegacySharedAccountFactory accountWithJSONDictionary:jsonDictionary error:&error]; + XCTAssertNil(account); + XCTAssertNotNil(error); +} + +- (void)testAccountWithJSONDictionary_whenTypeADAL_shouldReturnADALAccount +{ + NSDictionary *jsonDictionary = [self sampleJSONDictionaryWithAccountType:@"ADAL"]; + + NSError *error = nil; + MSALLegacySharedAccount *account = [MSALLegacySharedAccountFactory accountWithJSONDictionary:jsonDictionary error:&error]; + XCTAssertNotNil(account); + XCTAssertNil(error); + XCTAssertTrue([account isKindOfClass:[MSALLegacySharedADALAccount class]]); +} + +- (void)testAccountWithJSONDictionary_whenTypeMSA_shouldReturnMSAAccount +{ + NSDictionary *jsonDictionary = [self sampleJSONDictionaryWithAccountType:@"MSA"]; + + NSError *error = nil; + MSALLegacySharedAccount *account = [MSALLegacySharedAccountFactory accountWithJSONDictionary:jsonDictionary error:&error]; + XCTAssertNotNil(account); + XCTAssertNil(error); + XCTAssertTrue([account isKindOfClass:[MSALLegacySharedMSAAccount class]]); +} + +#pragma mark - Helpers + +- (NSDictionary *)sampleJSONDictionaryWithAccountType:(NSString *)accountType +{ + return @{@"authEndpointUrl": @"https://contoso.com/common", + @"id": [NSUUID UUID].UUIDString, + @"environment": @"PROD", + @"oid": [NSUUID UUID].UUIDString, + @"cid": @"40c03bac188d0d10", + @"originAppId": @"com.myapp.app", + @"tenantDisplayName": @"", + @"type": accountType ?: [NSNull null], + @"tenantId": [NSUUID UUID].UUIDString, + @"username": @"user@contoso.com" + }; +} + +@end diff --git a/MSAL/test/unit/ios/external-cache/MSALLegacySharedAccountTestUtil.h b/MSAL/test/unit/ios/external-cache/MSALLegacySharedAccountTestUtil.h new file mode 100644 index 0000000000..7ab2c7e338 --- /dev/null +++ b/MSAL/test/unit/ios/external-cache/MSALLegacySharedAccountTestUtil.h @@ -0,0 +1,47 @@ +//------------------------------------------------------------------------------ +// +// 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 + +extern NSString * _Nonnull const MSALDefaultTestMsaUid; +extern NSString * _Nonnull const MSALDefaultTestMsaCid; + +@interface MSALLegacySharedAccountTestUtil : NSObject + ++ (nullable MSALAccount *)testADALAccount; ++ (nullable MSALAccount *)testMSAAccount; + ++ (nonnull NSDictionary *)sampleADALJSONDictionary; ++ (nonnull NSDictionary *)sampleADALJSONDictionaryWithAccountId:(nullable NSString *)accountIdentifier + objectId:(nullable NSString *)objectId + tenantId:(nullable NSString *)tenantId + username:(nullable NSString *)username; + ++ (nonnull NSDictionary *)sampleMSAJSONDictionary; ++ (nonnull NSDictionary *)sampleMSAJSONDictionaryWithAccountId:(nullable NSString *)accountIdentifier; + +@end diff --git a/MSAL/test/unit/ios/external-cache/MSALLegacySharedAccountTestUtil.m b/MSAL/test/unit/ios/external-cache/MSALLegacySharedAccountTestUtil.m new file mode 100644 index 0000000000..3fa7cfda21 --- /dev/null +++ b/MSAL/test/unit/ios/external-cache/MSALLegacySharedAccountTestUtil.m @@ -0,0 +1,118 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALLegacySharedAccountTestUtil.h" +#import "MSALAccount+Internal.h" +#import "MSALAccountId+Internal.h" +#import "MSIDConstants.h" + +NSString *const MSALDefaultTestMsaUid = @"00000000-0000-0000-40c0-3bac188d0d10"; +NSString *const MSALDefaultTestMsaCid = @"40c03bac188d0d10"; + +@implementation MSALLegacySharedAccountTestUtil + ++ (MSALAccount *)testADALAccount +{ + MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:@"uid.utid" + objectId:@"uid" + tenantId:@"utid"]; + + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"user@contoso.com" + homeAccountId:accountId + environment:@"login.microsoftonline.com" + tenantProfiles:nil]; + + account.accountClaims = @{@"name": @"Contoso User", + @"oid": @"uid", + @"tid": @"utid" + }; + + return account; +} + ++ (MSALAccount *)testMSAAccount +{ + NSString *accountidentifier = [NSString stringWithFormat:@"%@.%@", MSALDefaultTestMsaUid, MSID_DEFAULT_MSA_TENANTID.lowercaseString]; + MSALAccountId *accountId = [[MSALAccountId alloc] initWithAccountIdentifier:accountidentifier + objectId:MSALDefaultTestMsaUid + tenantId:MSID_DEFAULT_MSA_TENANTID.lowercaseString]; + + MSALAccount *account = [[MSALAccount alloc] initWithUsername:@"user@contoso.com" + homeAccountId:accountId + environment:@"login.microsoftonline.com" + tenantProfiles:nil]; + + account.accountClaims = @{@"name": @"Contoso User", + @"oid": @"uid", + @"tid": @"utid" + }; + + return account; +} + ++ (NSDictionary *)sampleADALJSONDictionary +{ + return [self sampleADALJSONDictionaryWithAccountId:nil objectId:nil tenantId:nil username:nil]; +} + ++ (NSDictionary *)sampleADALJSONDictionaryWithAccountId:(NSString *)accountIdentifier + objectId:(NSString *)objectId + tenantId:(NSString *)tenantId + username:(NSString *)username +{ + return @{@"authEndpointUrl": @"https://login.windows.net/common/oauth2/authorize", + @"id": accountIdentifier ?: [NSUUID UUID].UUIDString, + @"environment": @"PROD", + @"oid": objectId ?: [NSUUID UUID].UUIDString, + @"originAppId": @"com.myapp.app", + @"tenantDisplayName": @"", + @"type": @"ADAL", + @"displayName": @"myDisplayName.contoso.user", + @"tenantId": tenantId ?: [NSUUID UUID].UUIDString, + @"username": username ?: @"user@contoso.com" + }; +} + ++ (NSDictionary *)sampleMSAJSONDictionary +{ + return [self sampleMSAJSONDictionaryWithAccountId:nil]; +} + ++ (NSDictionary *)sampleMSAJSONDictionaryWithAccountId:(NSString *)accountIdentifier +{ + return @{@"cid": MSALDefaultTestMsaCid, + @"email": @"user@outlook.com", + @"id": accountIdentifier ?: [NSUUID UUID].UUIDString, + @"originAppId": @"com.myapp.app", + @"type": @"MSA", + @"displayName": @"MyDisplayName", + @"additionalProperties": @{@"myprop1": @"myprop2"}, + @"additionalfield1": @"additionalvalue1" + }; +} + +@end diff --git a/MSAL/test/unit/ios/external-cache/MSALLegacySharedAccountTests.m b/MSAL/test/unit/ios/external-cache/MSALLegacySharedAccountTests.m new file mode 100644 index 0000000000..d490d51079 --- /dev/null +++ b/MSAL/test/unit/ios/external-cache/MSALLegacySharedAccountTests.m @@ -0,0 +1,243 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALLegacySharedAccount.h" +#import "MSALAccountEnumerationParameters.h" +#import "MSALTestConstants.h" +#import "MSALTestBundle.h" +#import "MSALAccount+Internal.h" +#import "MSALAccountId+Internal.h" +#import "MSALLegacySharedAccountTestUtil.h" + +@interface MSALLegacySharedAccountTests : XCTestCase + +@end + +@implementation MSALLegacySharedAccountTests + +#pragma mark - Init + +- (void)testInitWithJSONDictionary_whenAccountTypeMissing_shouldReturnNilAndFillError +{ + NSMutableDictionary *jsonDictionary = [[MSALLegacySharedAccountTestUtil sampleADALJSONDictionary] mutableCopy]; + jsonDictionary[@"type"] = nil; + + NSError *error = nil; + MSALLegacySharedAccount *account = [[MSALLegacySharedAccount alloc] initWithJSONDictionary:jsonDictionary error:&error]; + XCTAssertNil(account); + XCTAssertNotNil(error); + XCTAssertEqual(error.code, MSIDErrorInternal); + XCTAssertEqualObjects(error.domain, MSIDErrorDomain); + XCTAssertEqualObjects(error.userInfo[MSIDErrorDescriptionKey], @"Unexpected shared account found without type or identifier"); +} + +- (void)testInitWithJSONDictionary_whenIdentifierMissing_shouldReturnNilAndFillError +{ + NSMutableDictionary *jsonDictionary = [[MSALLegacySharedAccountTestUtil sampleADALJSONDictionary] mutableCopy]; + jsonDictionary[@"id"] = nil; + + NSError *error = nil; + MSALLegacySharedAccount *account = [[MSALLegacySharedAccount alloc] initWithJSONDictionary:jsonDictionary error:&error]; + XCTAssertNil(account); + XCTAssertNotNil(error); + XCTAssertEqual(error.code, MSIDErrorInternal); + XCTAssertEqualObjects(error.domain, MSIDErrorDomain); + XCTAssertEqualObjects(error.userInfo[MSIDErrorDescriptionKey], @"Unexpected shared account found without type or identifier"); +} + +- (void)testInitWithJSONDictionary_whenAllMandatoryFieldsPresent_shouldReturnNotNilResultAndNilError +{ + NSString *accountId = [NSUUID UUID].UUIDString; + NSMutableDictionary *jsonDictionary = [[MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:accountId objectId:nil tenantId:nil username:nil] mutableCopy]; + NSDictionary *signinStatusDict = @{@"com.microsoft.myapp": @"SignedIn", + @"com.microsoft.myapp2": @"SignedOut" + }; + jsonDictionary[@"signInStatus"] = signinStatusDict; + + NSError *error = nil; + MSALLegacySharedAccount *account = [[MSALLegacySharedAccount alloc] initWithJSONDictionary:jsonDictionary error:&error]; + XCTAssertNotNil(account); + XCTAssertNil(error); + + XCTAssertEqualObjects(account.accountType, @"ADAL"); + XCTAssertEqualObjects(account.accountIdentifier, accountId); + XCTAssertEqualObjects(account.signinStatusDictionary, signinStatusDict); +} + +- (void)testInitWithJSONDictionary_whenFieldsOfWrongType_shouldReturnNilAndFillError +{ + NSMutableDictionary *jsonDictionary = [[MSALLegacySharedAccountTestUtil sampleADALJSONDictionary] mutableCopy]; + jsonDictionary[@"type"] = [NSNull null]; + jsonDictionary[@"id"] = [NSNumber numberWithInteger:5]; + + NSError *error = nil; + MSALLegacySharedAccount *account = [[MSALLegacySharedAccount alloc] initWithJSONDictionary:jsonDictionary error:&error]; + XCTAssertNil(account); + XCTAssertNotNil(error); + XCTAssertEqual(error.code, MSIDErrorInternal); + XCTAssertEqualObjects(error.domain, MSIDErrorDomain); + XCTAssertEqualObjects(error.userInfo[MSIDErrorDescriptionKey], @"Unexpected shared account found without type or identifier"); +} + +#pragma mark - matchesParameters + +- (void)testMatchesParameters_whenNilParameters_shouldReturnYES +{ + NSDictionary *jsonDictionary = [MSALLegacySharedAccountTestUtil sampleADALJSONDictionary]; + MSALLegacySharedAccount *account = [[MSALLegacySharedAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + MSALAccountEnumerationParameters *params = nil; + BOOL result = [account matchesParameters:params]; + XCTAssertTrue(result); +} + +- (void)testMatchesParameters_whenReturnOnlySignedInAccountsNO_andAppSignedOut_shouldReturnYES +{ + NSMutableDictionary *jsonDictionary = [[MSALLegacySharedAccountTestUtil sampleADALJSONDictionary] mutableCopy]; + + NSDictionary *signinStatusDict = @{[[NSBundle mainBundle] bundleIdentifier]: @"SignedOut"}; + jsonDictionary[@"signInStatus"] = signinStatusDict; + + MSALLegacySharedAccount *account = [[MSALLegacySharedAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + MSALAccountEnumerationParameters *params = [MSALAccountEnumerationParameters new]; + params.returnOnlySignedInAccounts = NO; + BOOL result = [account matchesParameters:params]; + XCTAssertTrue(result); +} + +- (void)testMatchesParameters_whenReturnOnlySignedInAccountsYES_andAppSignedIn_shouldReturnYES +{ + NSMutableDictionary *jsonDictionary = [[MSALLegacySharedAccountTestUtil sampleADALJSONDictionary] mutableCopy]; + + NSDictionary *signinStatusDict = @{[[NSBundle mainBundle] bundleIdentifier] : @"SignedIn"}; + jsonDictionary[@"signInStatus"] = signinStatusDict; + + MSALLegacySharedAccount *account = [[MSALLegacySharedAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + MSALAccountEnumerationParameters *params = [MSALAccountEnumerationParameters new]; + params.returnOnlySignedInAccounts = YES; + BOOL result = [account matchesParameters:params]; + XCTAssertTrue(result); +} + +- (void)testMatchesParameters_whenReturnOnlySignedInAccountsYES_andAppSignedOut_shouldReturnNO +{ + NSMutableDictionary *jsonDictionary = [[MSALLegacySharedAccountTestUtil sampleADALJSONDictionary] mutableCopy]; + + NSDictionary *signinStatusDict = @{[[NSBundle mainBundle] bundleIdentifier]: @"SignedOut"}; + jsonDictionary[@"signInStatus"] = signinStatusDict; + + MSALLegacySharedAccount *account = [[MSALLegacySharedAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + MSALAccountEnumerationParameters *params = [MSALAccountEnumerationParameters new]; + params.returnOnlySignedInAccounts = YES; + BOOL result = [account matchesParameters:params]; + XCTAssertFalse(result); +} + +#pragma mark - updateAccountWithMSALAccount + +- (void)testUpdateAccountWithMSALAccount_whenV1Account_shouldReturnYesAndNilError_andNotUpdate +{ + NSMutableDictionary *jsonDictionary = [[MSALLegacySharedAccountTestUtil sampleADALJSONDictionary] mutableCopy]; + MSALLegacySharedAccount *account = [[MSALLegacySharedAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + NSError *updateError = nil; + BOOL result = [account updateAccountWithMSALAccount:[MSALLegacySharedAccountTestUtil testADALAccount] + applicationName:@"MyApp" + operation:MSALLegacySharedAccountRemoveOperation + accountVersion:MSALLegacySharedAccountVersionV1 + error:&updateError]; + + XCTAssertTrue(result); + XCTAssertNil(updateError); + XCTAssertEqualObjects([account jsonDictionary], jsonDictionary); +} + +- (void)testUpdateAccountWithMSALAccount_whenRemoveOperation_shouldUpdateSigninStatusAndUpdatedDict +{ + NSString *accountId = [NSUUID UUID].UUIDString; + NSString *appIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + NSMutableDictionary *jsonDictionary = [[MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:accountId objectId:nil tenantId:nil username:nil] mutableCopy]; + NSDictionary *signinStatusDict = @{appIdentifier : @"SignedIn"}; + jsonDictionary[@"signInStatus"] = signinStatusDict; + + MSALLegacySharedAccount *account = [[MSALLegacySharedAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + NSError *updateError = nil; + BOOL result = [account updateAccountWithMSALAccount:[MSALLegacySharedAccountTestUtil testADALAccount] + applicationName:@"MyApp" + operation:MSALLegacySharedAccountRemoveOperation + accountVersion:MSALLegacySharedAccountVersionV2 + error:&updateError]; + + XCTAssertTrue(result); + XCTAssertNil(updateError); + XCTAssertNotEqualObjects([account jsonDictionary], jsonDictionary); + NSString *newSigninStatus = [account jsonDictionary][@"signInStatus"][appIdentifier]; + XCTAssertEqualObjects(newSigninStatus, @"SignedOut"); + NSString *updatedByStatus = [account jsonDictionary][@"additionalProperties"][@"updatedBy"]; + XCTAssertEqualObjects(updatedByStatus, @"MyApp"); + NSString *updatedAt = [account jsonDictionary][@"additionalProperties"][@"updatedAt"]; + XCTAssertNotNil(updatedAt); + XCTAssertEqualObjects(account.accountType, @"ADAL"); + XCTAssertEqualObjects(account.accountIdentifier, accountId); +} + +- (void)testUpdateAccountWithMSALAccount_whenUpdateOperation_shouldUpdateSigninStatusAndUpdatedDict +{ + NSString *accountId = [NSUUID UUID].UUIDString; + NSString *appIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + NSMutableDictionary *jsonDictionary = [[MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:accountId objectId:nil tenantId:nil username:nil] mutableCopy]; + NSDictionary *signinStatusDict = @{appIdentifier : @"SignedOut"}; + jsonDictionary[@"signInStatus"] = signinStatusDict; + + MSALLegacySharedAccount *account = [[MSALLegacySharedAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + NSError *updateError = nil; + BOOL result = [account updateAccountWithMSALAccount:[MSALLegacySharedAccountTestUtil testADALAccount] + applicationName:@"MyApp" + operation:MSALLegacySharedAccountUpdateOperation + accountVersion:MSALLegacySharedAccountVersionV3 + error:&updateError]; + + XCTAssertTrue(result); + XCTAssertNil(updateError); + XCTAssertNotEqualObjects([account jsonDictionary], jsonDictionary); + NSString *newSigninStatus = [account jsonDictionary][@"signInStatus"][appIdentifier]; + XCTAssertEqualObjects(newSigninStatus, @"SignedIn"); + NSString *updatedByStatus = [account jsonDictionary][@"additionalProperties"][@"updatedBy"]; + XCTAssertEqualObjects(updatedByStatus, @"MyApp"); + NSString *updatedAt = [account jsonDictionary][@"additionalProperties"][@"updatedAt"]; + XCTAssertNotNil(updatedAt); + XCTAssertEqualObjects(account.accountType, @"ADAL"); + XCTAssertEqualObjects(account.accountIdentifier, accountId); +} + +@end diff --git a/MSAL/test/unit/ios/external-cache/MSALLegacySharedAccountsProviderTests.m b/MSAL/test/unit/ios/external-cache/MSALLegacySharedAccountsProviderTests.m new file mode 100644 index 0000000000..a40a151f4a --- /dev/null +++ b/MSAL/test/unit/ios/external-cache/MSALLegacySharedAccountsProviderTests.m @@ -0,0 +1,502 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALLegacySharedAccountsProvider.h" +#import "MSIDKeychainTokenCache.h" +#import "MSIDJsonObject.h" +#import "MSIDCacheItemJsonSerializer.h" +#import "MSIDCacheKey.h" +#import "MSALAccount+Internal.h" +#import "MSALAccountId+Internal.h" +#import "MSALTenantProfile+Internal.h" +#import "MSIDConstants.h" +#import "MSALLegacySharedAccountTestUtil.h" +#import "MSALAccountEnumerationParameters.h" + +@interface MSALLegacySharedAccountsProviderTests : XCTestCase + +@property (nonatomic) MSALLegacySharedAccountsProvider *accountsProvider; +@property (nonatomic) MSIDKeychainTokenCache *keychainTokenCache; + +@end + +@implementation MSALLegacySharedAccountsProviderTests + +#pragma mark - Setup + +- (void)setUp +{ + [super setUp]; + self.accountsProvider = [[MSALLegacySharedAccountsProvider alloc] initWithSharedKeychainAccessGroup:@"com.microsoft.adalcache" + serviceIdentifier:@"MyAccountService" + applicationIdentifier:@"MyApp"]; + + self.keychainTokenCache = [[MSIDKeychainTokenCache alloc] initWithGroup:@"com.microsoft.adalcache"]; + [self.keychainTokenCache clearWithContext:nil error:nil]; +} + +#pragma mark - Read + +- (void)testAccountsWithParameters_whenNoAccountsInCache_shouldReturnEmptyResultsList +{ + MSALAccountEnumerationParameters *parameters = [MSALAccountEnumerationParameters new]; + + NSError *error = nil; + NSArray *results = [self.accountsProvider accountsWithParameters:parameters error:&error]; + XCTAssertNil(error); + XCTAssertNotNil(results); + XCTAssertEqual([results count], 0); +} + +- (void)testAccountsWithParameters_whenEmptyBlobInCache_shouldReturnEmptyResultsList +{ + NSDictionary *accountsBlob = @{@"lastWriteTimestamp": @"123474849"}; + [self saveAccountsBlob:accountsBlob version:@"AccountsV1"]; + + MSALAccountEnumerationParameters *parameters = [MSALAccountEnumerationParameters new]; + + NSError *error = nil; + NSArray *results = [self.accountsProvider accountsWithParameters:parameters error:&error]; + XCTAssertNil(error); + XCTAssertNotNil(results); + XCTAssertEqual([results count], 0); +} + +- (void)testAccountsWithParameters_whenMatchingAccountInOlderVersion_shouldReturnThatAccount +{ + NSString *accountId = [NSUUID UUID].UUIDString; + NSDictionary *singleAccountBlob = [MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:accountId + objectId:nil + tenantId:nil + username:@"user@contoso.com"]; + NSDictionary *accountsBlob = @{@"lastWriteTimestamp": @"123474849", accountId : singleAccountBlob}; + [self saveAccountsBlob:accountsBlob version:@"AccountsV2"]; + + MSALAccountEnumerationParameters *parameters = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:nil username:@"user@contoso.com"]; + parameters.returnOnlySignedInAccounts = NO; + + NSError *error = nil; + NSArray *results = [self.accountsProvider accountsWithParameters:parameters error:&error]; + XCTAssertNil(error); + XCTAssertNotNil(results); + XCTAssertEqual([results count], 1); +} + +- (void)testAccountsWithParameters_whenMatchingAccountInLatestVersion_shouldReturnThatAccount +{ + NSString *accountId1 = [NSUUID UUID].UUIDString; + NSString *accountId2 = [NSUUID UUID].UUIDString; + NSDictionary *accountBlob1 = [MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:accountId1 + objectId:@"oid1" + tenantId:nil + username:@"user@CONTOSO.com"]; + + NSDictionary *accountBlob2 = [MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:accountId2 + objectId:@"oid2" + tenantId:nil + username:@"user2@contoso.com"]; + + NSDictionary *accountsBlob = @{@"lastWriteTimestamp": @"123474849", accountId1 : accountBlob1, accountId2 : accountBlob2}; + [self saveAccountsBlob:accountsBlob version:@"AccountsV3"]; + NSString *accountId3 = [NSUUID UUID].UUIDString; + NSDictionary *accountBlob3 = [MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:accountId3 + objectId:@"oid3" + tenantId:nil + username:@"user@CONTOSO.com"]; + + NSDictionary *oldAccountsBlob = @{@"lastWriteTimestamp": @"123474848", accountId3 : accountBlob3}; + [self saveAccountsBlob:oldAccountsBlob version:@"AccountsV2"]; + + MSALAccountEnumerationParameters *parameters = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:nil username:@"user@contoso.com"]; + parameters.returnOnlySignedInAccounts = NO; + + NSError *error = nil; + NSArray *results = [self.accountsProvider accountsWithParameters:parameters error:&error]; + XCTAssertNil(error); + XCTAssertNotNil(results); + XCTAssertEqual([results count], 1); + id account = results[0]; + XCTAssertTrue([account.identifier hasPrefix:@"oid1"]); + XCTAssertEqualObjects(account.username, @"user@CONTOSO.com"); + XCTAssertEqualObjects(account.environment, @"login.windows.net"); +} + +- (void)testAccountsWithParameters_whenAccountsPresent_butNotMatching_shouldReturnNilAndNilError +{ + NSString *accountId = [NSUUID UUID].UUIDString; + NSDictionary *singleAccountBlob = [MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:accountId + objectId:nil + tenantId:nil + username:@"user2@contoso.com"]; + NSDictionary *accountsBlob = @{@"lastWriteTimestamp": @"123474849", accountId : singleAccountBlob}; + [self saveAccountsBlob:accountsBlob version:@"AccountsV3"]; + + MSALAccountEnumerationParameters *parameters = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:nil username:@"user@contoso.com"]; + parameters.returnOnlySignedInAccounts = NO; + + NSError *error = nil; + NSArray *results = [self.accountsProvider accountsWithParameters:parameters error:&error]; + XCTAssertNil(error); + XCTAssertNotNil(results); + XCTAssertEqual([results count], 0); +} + +- (void)testAccountsWithParameters_whenCorruptSingleItem_shouldIgnoreAccount +{ + NSString *accountId = [NSUUID UUID].UUIDString; + NSMutableDictionary *singleAccountBlob = [[MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:accountId objectId:nil tenantId:nil username:@"user@contoso.com"] mutableCopy]; + singleAccountBlob[@"type"] = @"Unknown"; + NSDictionary *accountsBlob = @{@"lastWriteTimestamp": @"123474849", accountId : singleAccountBlob}; + [self saveAccountsBlob:accountsBlob version:@"AccountsV3"]; + + MSALAccountEnumerationParameters *parameters = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:nil username:@"user@contoso.com"]; + parameters.returnOnlySignedInAccounts = NO; + + NSError *error = nil; + NSArray *results = [self.accountsProvider accountsWithParameters:parameters error:&error]; + XCTAssertNil(error); + XCTAssertNotNil(results); + XCTAssertEqual([results count], 0); +} + +#pragma mark - Update + +- (void)testUpdateAccount_whenEmptyBlob_shouldAddAccount +{ + self.accountsProvider.sharedAccountMode = MSALLegacySharedAccountModeReadWrite; + + NSDictionary *accountsBlob = @{@"lastWriteTimestamp": @"123474849"}; + [self saveAccountsBlob:accountsBlob version:@"AccountsV3"]; + + MSALAccount *testAccount = [MSALLegacySharedAccountTestUtil testADALAccount]; + NSError *error = nil; + BOOL result = [self.accountsProvider updateAccount:testAccount idTokenClaims:testAccount.accountClaims error:&error]; + + XCTAssertTrue(result); + XCTAssertNil(error); + + [self verifyBlobCountWithV1Count:1 v2Count:2 v3Count:2]; +} + +- (void)testUpdateAccount_whenCorruptSingleEntry_shouldAddAccount +{ + self.accountsProvider.sharedAccountMode = MSALLegacySharedAccountModeReadWrite; + + NSString *accountId = [NSUUID UUID].UUIDString; + NSMutableDictionary *singleAccountBlob = [[MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:accountId objectId:nil tenantId:nil username:@"user@contoso.com"] mutableCopy]; + singleAccountBlob[@"type"] = @"Unknown"; + NSDictionary *accountsBlob = @{@"lastWriteTimestamp": @"123474849", accountId : singleAccountBlob}; + [self saveAccountsBlob:accountsBlob version:@"AccountsV3"]; + + MSALAccount *testAccount = [MSALLegacySharedAccountTestUtil testADALAccount]; + NSError *error = nil; + BOOL result = [self.accountsProvider updateAccount:testAccount idTokenClaims:testAccount.accountClaims error:&error]; + + XCTAssertTrue(result); + XCTAssertNil(error); + + [self verifyBlobCountWithV1Count:1 v2Count:2 v3Count:3]; +} + +- (void)testUpdateAccount_whenMatchingADALAccountsPresent_shouldUpdateAccounts +{ + self.accountsProvider.sharedAccountMode = MSALLegacySharedAccountModeReadWrite; + + NSString *accountId = [NSUUID UUID].UUIDString; + NSDictionary *singleAccountBlob = [MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:accountId objectId:@"uid" tenantId:nil username:@"old@contoso.com"]; + NSDictionary *accountsBlob = @{@"lastWriteTimestamp": @"123474849", accountId : singleAccountBlob}; + [self saveAccountsBlob:accountsBlob version:@"AccountsV3"]; + [self saveAccountsBlob:accountsBlob version:@"AccountsV2"]; + + MSALAccount *testAccount = [MSALLegacySharedAccountTestUtil testADALAccount]; + NSError *error = nil; + BOOL result = [self.accountsProvider updateAccount:testAccount idTokenClaims:testAccount.accountClaims error:&error]; + + XCTAssertTrue(result); + XCTAssertNil(error); + + [self verifyBlobCountWithV1Count:1 v2Count:2 v3Count:2]; + + NSDictionary *v2Blob = [self readBlobWithVersion:@"AccountsV2"]; + NSString *accountIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + XCTAssertEqualObjects(v2Blob[accountId][@"signInStatus"][accountIdentifier], @"SignedIn"); + XCTAssertEqualObjects(v2Blob[accountId][@"username"], @"user@contoso.com"); + + NSDictionary *v3Blob = [self readBlobWithVersion:@"AccountsV3"]; + XCTAssertEqualObjects(v3Blob[accountId][@"signInStatus"][accountIdentifier], @"SignedIn"); + XCTAssertEqualObjects(v3Blob[accountId][@"username"], @"user@contoso.com"); +} + +- (void)testUpdateAccount_whenMatchingMSAAccountsPresent_shouldUpdateAccounts +{ + self.accountsProvider.sharedAccountMode = MSALLegacySharedAccountModeReadWrite; + + NSString *accountId = [NSUUID UUID].UUIDString; + NSDictionary *singleAccountBlob = [MSALLegacySharedAccountTestUtil sampleMSAJSONDictionaryWithAccountId:accountId]; + NSDictionary *accountsBlob = @{@"lastWriteTimestamp": @"123474849", accountId : singleAccountBlob}; + [self saveAccountsBlob:accountsBlob version:@"AccountsV3"]; + [self saveAccountsBlob:accountsBlob version:@"AccountsV2"]; + + MSALAccount *testAccount = [MSALLegacySharedAccountTestUtil testMSAAccount]; + NSError *error = nil; + BOOL result = [self.accountsProvider updateAccount:testAccount idTokenClaims:testAccount.accountClaims error:&error]; + + XCTAssertTrue(result); + XCTAssertNil(error); + + [self verifyBlobCountWithV1Count:1 v2Count:2 v3Count:2]; + + NSDictionary *v2Blob = [self readBlobWithVersion:@"AccountsV2"]; + NSString *accountIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + XCTAssertEqualObjects(v2Blob[accountId][@"signInStatus"][accountIdentifier], @"SignedIn"); + XCTAssertEqualObjects(v2Blob[accountId][@"username"], @"user@contoso.com"); + + NSDictionary *v3Blob = [self readBlobWithVersion:@"AccountsV3"]; + XCTAssertEqualObjects(v3Blob[accountId][@"signInStatus"][accountIdentifier], @"SignedIn"); + XCTAssertEqualObjects(v3Blob[accountId][@"username"], @"user@contoso.com"); +} + +- (void)testUpdateAccount_whenNonMatchingAccountPresent_shouldAddAccount +{ + self.accountsProvider.sharedAccountMode = MSALLegacySharedAccountModeReadWrite; + + NSString *accountId = [NSUUID UUID].UUIDString; + NSDictionary *singleAccountBlob = [MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:accountId objectId:@"uid2" tenantId:nil username:@"old@contoso.com"]; + NSDictionary *accountsBlob = @{@"lastWriteTimestamp": @"123474849", accountId : singleAccountBlob}; + [self saveAccountsBlob:accountsBlob version:@"AccountsV3"]; + [self saveAccountsBlob:accountsBlob version:@"AccountsV2"]; + + MSALAccount *testAccount = [MSALLegacySharedAccountTestUtil testADALAccount]; + NSError *error = nil; + BOOL result = [self.accountsProvider updateAccount:testAccount idTokenClaims:testAccount.accountClaims error:&error]; + + XCTAssertTrue(result); + XCTAssertNil(error); + + [self verifyBlobCountWithV1Count:1 v2Count:3 v3Count:3]; +} + +#pragma mark - Remove + +- (void)testRemoveAccount_whenEmptyBlob_shouldUpdateTimeStamp +{ + self.accountsProvider.sharedAccountMode = MSALLegacySharedAccountModeReadWrite; + + NSDictionary *accountsBlob = @{@"lastWriteTimestamp": @"123474849"}; + [self saveAccountsBlob:accountsBlob version:@"AccountsV3"]; + + MSALAccount *testAccount = [MSALLegacySharedAccountTestUtil testADALAccount]; + NSError *error = nil; + BOOL result = [self.accountsProvider removeAccount:testAccount tenantProfiles:nil error:&error]; + + XCTAssertTrue(result); + XCTAssertNil(error); + + [self verifyBlobCountWithV1Count:1 v2Count:1 v3Count:1]; +} + +- (void)testRemoveAccount_whenCorruptSingleEntry_shouldUpdateTimestamp +{ + self.accountsProvider.sharedAccountMode = MSALLegacySharedAccountModeReadWrite; + + NSString *accountId = [NSUUID UUID].UUIDString; + NSMutableDictionary *singleAccountBlob = [[MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:accountId objectId:nil tenantId:nil username:@"user@contoso.com"] mutableCopy]; + singleAccountBlob[@"type"] = @"Unknown"; + NSDictionary *accountsBlob = @{@"lastWriteTimestamp": @"123474849", accountId : singleAccountBlob}; + [self saveAccountsBlob:accountsBlob version:@"AccountsV3"]; + + MSALAccount *testAccount = [MSALLegacySharedAccountTestUtil testADALAccount]; + NSError *error = nil; + BOOL result = [self.accountsProvider removeAccount:testAccount tenantProfiles:nil error:&error]; + + XCTAssertTrue(result); + XCTAssertNil(error); + + [self verifyBlobCountWithV1Count:1 v2Count:1 v3Count:2]; + + NSMutableDictionary *v3Blob = [[self readBlobWithVersion:@"AccountsV3"] mutableCopy]; + XCTAssertEqualObjects(v3Blob[accountId], singleAccountBlob); // make sure we didn't touch corrupted dict +} + +- (void)testRemoveAccount_whenMatchingAccountsPresent_shouldUpdateAccountsWithSignedOutStatus +{ + self.accountsProvider.sharedAccountMode = MSALLegacySharedAccountModeReadWrite; + + NSString *accountId = [NSUUID UUID].UUIDString; + NSDictionary *singleAccountBlob = [MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:accountId objectId:@"uid" tenantId:nil username:@"old@contoso.com"]; + NSDictionary *accountsBlob = @{@"lastWriteTimestamp": @"123474849", accountId : singleAccountBlob}; + [self saveAccountsBlob:accountsBlob version:@"AccountsV3"]; + [self saveAccountsBlob:accountsBlob version:@"AccountsV2"]; + + MSALAccount *testAccount = [MSALLegacySharedAccountTestUtil testADALAccount]; + NSError *error = nil; + BOOL result = [self.accountsProvider removeAccount:testAccount tenantProfiles:nil error:&error]; + + XCTAssertTrue(result); + XCTAssertNil(error); + + [self verifyBlobCountWithV1Count:1 v2Count:2 v3Count:2]; + + NSDictionary *v2Blob = [self readBlobWithVersion:@"AccountsV2"]; + NSString *accountIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + XCTAssertEqualObjects(v2Blob[accountId][@"signInStatus"][accountIdentifier], @"SignedOut"); + XCTAssertEqualObjects(v2Blob[accountId][@"username"], @"user@contoso.com"); + + NSDictionary *v3Blob = [self readBlobWithVersion:@"AccountsV3"]; + XCTAssertEqualObjects(v3Blob[accountId][@"signInStatus"][accountIdentifier], @"SignedOut"); + XCTAssertEqualObjects(v3Blob[accountId][@"username"], @"user@contoso.com"); +} + +- (void)testRemoveAccount_whenTenantProfilesPassed_andMatchingAccountsPresent_shouldUpdateAccountsWithSignedOutStatus +{ + self.accountsProvider.sharedAccountMode = MSALLegacySharedAccountModeReadWrite; + + NSString *accountId = [NSUUID UUID].UUIDString; + NSDictionary *singleAccountBlob = [MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:accountId objectId:@"uid" tenantId:nil username:@"old@contoso.com"]; + NSDictionary *accountsBlob = @{@"lastWriteTimestamp": @"123474849", accountId : singleAccountBlob}; + [self saveAccountsBlob:accountsBlob version:@"AccountsV3"]; + [self saveAccountsBlob:accountsBlob version:@"AccountsV2"]; + + MSALAccount *testAccount = [MSALLegacySharedAccountTestUtil testADALAccount]; + NSError *error = nil; + MSALTenantProfile *tenantProfile1 = [[MSALTenantProfile alloc] initWithIdentifier:@"uid" + tenantId:@"tid" + environment:@"login.microoftonline.com" + isHomeTenantProfile:YES + claims:nil]; + + MSALTenantProfile *tenantProfile2 = [[MSALTenantProfile alloc] initWithIdentifier:@"guest-uid" + tenantId:@"guest-tid" + environment:@"login.microoftonline.com" + isHomeTenantProfile:YES + claims:nil]; + + BOOL result = [self.accountsProvider removeAccount:testAccount tenantProfiles:@[tenantProfile2, tenantProfile1] error:&error]; + + XCTAssertTrue(result); + XCTAssertNil(error); + + [self verifyBlobCountWithV1Count:1 v2Count:2 v3Count:2]; + + NSDictionary *v2Blob = [self readBlobWithVersion:@"AccountsV2"]; + NSString *accountIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + XCTAssertEqualObjects(v2Blob[accountId][@"signInStatus"][accountIdentifier], @"SignedOut"); + XCTAssertEqualObjects(v2Blob[accountId][@"username"], @"user@contoso.com"); + + NSDictionary *v3Blob = [self readBlobWithVersion:@"AccountsV3"]; + XCTAssertEqualObjects(v3Blob[accountId][@"signInStatus"][accountIdentifier], @"SignedOut"); + XCTAssertEqualObjects(v3Blob[accountId][@"username"], @"user@contoso.com"); +} + +- (void)testRemoveAccount_whenNonMatchingAccountPresent_shouldOnlyUpdateTimestamps +{ + self.accountsProvider.sharedAccountMode = MSALLegacySharedAccountModeReadWrite; + + NSString *accountId = [NSUUID UUID].UUIDString; + NSDictionary *singleAccountBlob = [MSALLegacySharedAccountTestUtil sampleADALJSONDictionaryWithAccountId:accountId objectId:@"uid2" tenantId:nil username:@"old@contoso.com"]; + NSDictionary *accountsBlob = @{@"lastWriteTimestamp": @"123474849", accountId : singleAccountBlob}; + [self saveAccountsBlob:accountsBlob version:@"AccountsV3"]; + [self saveAccountsBlob:accountsBlob version:@"AccountsV2"]; + + MSALAccount *testAccount = [MSALLegacySharedAccountTestUtil testADALAccount]; + NSError *error = nil; + BOOL result = [self.accountsProvider removeAccount:testAccount tenantProfiles:nil error:&error]; + + XCTAssertTrue(result); + XCTAssertNil(error); + + [self verifyBlobCountWithV1Count:1 v2Count:2 v3Count:2]; + + NSDictionary *v2Blob = [self readBlobWithVersion:@"AccountsV2"]; + XCTAssertEqualObjects(v2Blob[accountId], singleAccountBlob); + + NSDictionary *v3Blob = [self readBlobWithVersion:@"AccountsV3"]; + XCTAssertEqualObjects(v3Blob[accountId], singleAccountBlob); +} + +#pragma mark - Asserts + +- (void)verifyBlobCountWithV1Count:(NSUInteger)v1BlobCount + v2Count:(NSUInteger)v2BlobCount + v3Count:(NSUInteger)v3BlobCount +{ + NSDictionary *v1Blob = [self readBlobWithVersion:@"AccountsV1"]; + XCTAssertNotNil(v1Blob); + XCTAssertEqual([v1Blob count], v1BlobCount); + XCTAssertNotNil(v1Blob[@"lastWriteTimestamp"]); + + NSDictionary *v2Blob = [self readBlobWithVersion:@"AccountsV2"]; + XCTAssertNotNil(v2Blob); + XCTAssertEqual([v2Blob count], v2BlobCount); + XCTAssertNotNil(v2Blob[@"lastWriteTimestamp"]); + XCTAssertTrue([v2Blob[@"lastWriteTimestamp"] longValue] > [v1Blob[@"lastWriteTimestamp"] longValue]); + + NSDictionary *v3Blob = [self readBlobWithVersion:@"AccountsV3"]; + XCTAssertNotNil(v3Blob); + XCTAssertEqual([v3Blob count], v3BlobCount); + XCTAssertNotNil(v3Blob[@"lastWriteTimestamp"]); + XCTAssertTrue([v3Blob[@"lastWriteTimestamp"] longValue] > [v2Blob[@"lastWriteTimestamp"] longValue]); +} + +#pragma mark - Helpers + +- (void)saveAccountsBlob:(NSDictionary *)accountsBlob version:(NSString *)version +{ + MSIDJsonObject *jsonObject = [[MSIDJsonObject alloc] initWithJSONDictionary:accountsBlob error:nil]; + MSIDCacheKey *cacheKey = [[MSIDCacheKey alloc] initWithAccount:version + service:@"MyAccountService" + generic:nil + type:nil]; + + BOOL saveResult = [self.keychainTokenCache saveJsonObject:jsonObject + serializer:[MSIDCacheItemJsonSerializer new] + key:cacheKey + context:nil + error:nil]; + XCTAssertTrue(saveResult); +} + +- (NSDictionary *)readBlobWithVersion:(NSString *)version +{ + MSIDCacheKey *cacheKey = [[MSIDCacheKey alloc] initWithAccount:version + service:@"MyAccountService" + generic:nil + type:nil]; + + NSArray *results = [self.keychainTokenCache jsonObjectsWithKey:cacheKey + serializer:[MSIDCacheItemJsonSerializer new] + context:nil + error:nil]; + XCTAssertNotNil(results); + XCTAssertEqual([results count], 1); + + MSIDJsonObject *jsonObject = results[0]; + return [jsonObject jsonDictionary]; +} + +@end diff --git a/MSAL/test/unit/ios/external-cache/MSALLegacySharedMSAAccountTests.m b/MSAL/test/unit/ios/external-cache/MSALLegacySharedMSAAccountTests.m new file mode 100644 index 0000000000..50a49b3ece --- /dev/null +++ b/MSAL/test/unit/ios/external-cache/MSALLegacySharedMSAAccountTests.m @@ -0,0 +1,230 @@ +//------------------------------------------------------------------------------ +// +// 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 "MSALLegacySharedMSAAccount.h" +#import "MSALAccount+Internal.h" +#import "MSALAccountId+Internal.h" +#import "MSALAccountEnumerationParameters.h" +#import "MSIDConstants.h" +#import "MSALLegacySharedAccountTestUtil.h" + +@interface MSALLegacySharedMSAAccountTests : XCTestCase + +@end + +static NSString *kDefaultTestUid = @"00000000-0000-0000-40c0-3bac188d0d10"; +static NSString *kDefaultTestCid = @"40c03bac188d0d10"; + +@implementation MSALLegacySharedMSAAccountTests + +#pragma mark - Init + +- (void)testInitWithJSONDictionary_whenWrongAccountType_shouldReturnNilAndError +{ + NSMutableDictionary *jsonDictionary = [[MSALLegacySharedAccountTestUtil sampleMSAJSONDictionary] mutableCopy]; + jsonDictionary[@"type"] = @"ADAL"; + + NSError *error = nil; + MSALLegacySharedMSAAccount *account = [[MSALLegacySharedMSAAccount alloc] initWithJSONDictionary:jsonDictionary error:&error]; + XCTAssertNil(account); + XCTAssertNotNil(error); + XCTAssertEqual(error.code, MSIDErrorInternal); + XCTAssertEqualObjects(error.domain, MSIDErrorDomain); + XCTAssertEqualObjects(error.userInfo[MSIDErrorDescriptionKey], @"Unexpected account type"); +} + +- (void)testInitWithJSONDictionary_whenNilUID_shouldReturnNilAndFillError +{ + NSMutableDictionary *jsonDictionary = [[MSALLegacySharedAccountTestUtil sampleMSAJSONDictionary] mutableCopy]; + jsonDictionary[@"cid"] = nil; + + NSError *error = nil; + MSALLegacySharedMSAAccount *account = [[MSALLegacySharedMSAAccount alloc] initWithJSONDictionary:jsonDictionary error:&error]; + XCTAssertNil(account); + XCTAssertNotNil(error); + XCTAssertEqual(error.code, MSIDErrorInternal); + XCTAssertEqualObjects(error.domain, MSIDErrorDomain); + XCTAssertEqualObjects(error.userInfo[MSIDErrorDescriptionKey], @"Unexpected identifier found for MSA account"); +} + +- (void)testInitWithJSONDictionary_whenAllInformationPresent_shouldCreateAccount +{ + NSString *accountId = [NSUUID UUID].UUIDString.lowercaseString; + + NSDictionary *jsonDictionary = [MSALLegacySharedAccountTestUtil sampleMSAJSONDictionaryWithAccountId:accountId]; + + NSError *error = nil; + MSALLegacySharedMSAAccount *account = [[MSALLegacySharedMSAAccount alloc] initWithJSONDictionary:jsonDictionary error:&error]; + XCTAssertNotNil(account); + XCTAssertNil(error); + XCTAssertEqualObjects(account.accountType, @"MSA"); + XCTAssertEqualObjects(account.environment, @"login.windows.net"); + NSString *expectedIdentifier = [NSString stringWithFormat:@"%@.%@", kDefaultTestUid, MSID_DEFAULT_MSA_TENANTID.lowercaseString]; + XCTAssertEqualObjects(account.identifier, expectedIdentifier); + XCTAssertEqualObjects(account.accountIdentifier, accountId); + XCTAssertEqualObjects(account.username, @"user@outlook.com"); + XCTAssertEqualObjects(account.accountClaims[@"oid"], kDefaultTestUid); + XCTAssertEqualObjects(account.accountClaims[@"tid"], MSID_DEFAULT_MSA_TENANTID); +} + +#pragma mark - MatchesParameters + +- (void)testMatchesWithParameters_whenShouldHaveAssociatedRefreshTokenYES_AndAccountSignedOut_shouldReturnNO +{ + NSMutableDictionary *jsonDictionary = [[MSALLegacySharedAccountTestUtil sampleMSAJSONDictionary] mutableCopy]; + + NSDictionary *signinStatusDict = @{[[NSBundle mainBundle] bundleIdentifier]: @"SignedOut"}; + jsonDictionary[@"signInStatus"] = signinStatusDict; + + MSALLegacySharedMSAAccount *account = [[MSALLegacySharedMSAAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + MSALAccountEnumerationParameters *params = [MSALAccountEnumerationParameters new]; + params.returnOnlySignedInAccounts = YES; + BOOL result = [account matchesParameters:params]; + XCTAssertFalse(result); +} + +- (void)testMatchesWithParameters_whenNilParameters_shouldReturnYES +{ + NSDictionary *jsonDictionary = [MSALLegacySharedAccountTestUtil sampleMSAJSONDictionary]; + MSALLegacySharedMSAAccount *account = [[MSALLegacySharedMSAAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + MSALAccountEnumerationParameters *params = nil; + BOOL result = [account matchesParameters:params]; + XCTAssertTrue(result); +} + +- (void)testMatchesWithParameters_whenIdentifierNonNil_andMatchingIdentifier_shouldReturnYES +{ + NSDictionary *jsonDictionary = [MSALLegacySharedAccountTestUtil sampleMSAJSONDictionary]; + + MSALLegacySharedMSAAccount *account = [[MSALLegacySharedMSAAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + NSString *expectedIdentifier = [NSString stringWithFormat:@"%@.%@", kDefaultTestUid, MSID_DEFAULT_MSA_TENANTID.lowercaseString]; + MSALAccountEnumerationParameters *params = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:expectedIdentifier]; + params.returnOnlySignedInAccounts = NO; + BOOL result = [account matchesParameters:params]; + XCTAssertTrue(result); +} + +- (void)testMatchesWithParameters_whenIdentifierAndUsernameSet_andMatchingAllOptions_shouldReturnYES +{ + NSDictionary *jsonDictionary = [MSALLegacySharedAccountTestUtil sampleMSAJSONDictionary]; + + MSALLegacySharedMSAAccount *account = [[MSALLegacySharedMSAAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + NSString *expectedIdentifier = [NSString stringWithFormat:@"%@.%@", kDefaultTestUid, MSID_DEFAULT_MSA_TENANTID.lowercaseString]; + MSALAccountEnumerationParameters *params = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:expectedIdentifier username:@"user@outlook.com"]; + params.returnOnlySignedInAccounts = NO; + BOOL result = [account matchesParameters:params]; + XCTAssertTrue(result); +} + +- (void)testMatchesWithParameters_whenAllMatchignOptionsSet_andMatchingAllOptions_butDifferentCase_shouldReturnYES +{ + NSDictionary *jsonDictionary = [MSALLegacySharedAccountTestUtil sampleMSAJSONDictionary]; + + MSALLegacySharedMSAAccount *account = [[MSALLegacySharedMSAAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + NSString *expectedIdentifier = [NSString stringWithFormat:@"%@.%@", kDefaultTestUid.uppercaseString, MSID_DEFAULT_MSA_TENANTID]; + MSALAccountEnumerationParameters *params = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:expectedIdentifier username:@"USER@outlOOK.com"]; + params.returnOnlySignedInAccounts = NO; + BOOL result = [account matchesParameters:params]; + XCTAssertTrue(result); +} + +- (void)testMatchesWithParameters_whenTenantProfileIdentifierNonNil_shouldReturnNO +{ + NSDictionary *jsonDictionary = [MSALLegacySharedAccountTestUtil sampleMSAJSONDictionary]; + + MSALLegacySharedMSAAccount *account = [[MSALLegacySharedMSAAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + MSALAccountEnumerationParameters *params = [[MSALAccountEnumerationParameters alloc] initWithTenantProfileIdentifier:@"myoid"]; + params.returnOnlySignedInAccounts = NO; + BOOL result = [account matchesParameters:params]; + XCTAssertFalse(result); +} + +- (void)testMatchesWithParamaters_whenUsernameNonNil_andUsernameDifferent_shouldReturnNO +{ + NSDictionary *jsonDictionary = [MSALLegacySharedAccountTestUtil sampleMSAJSONDictionary]; + + MSALLegacySharedMSAAccount *account = [[MSALLegacySharedMSAAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + MSALAccountEnumerationParameters *params = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:nil username:@"user2@contoso.com"]; + params.returnOnlySignedInAccounts = NO; + BOOL result = [account matchesParameters:params]; + XCTAssertFalse(result); +} + +- (void)testMatchesWithParameters_whenIdentifierNonNil_andIdentifierDifferent_shouldReturnNO +{ + NSDictionary *jsonDictionary = [MSALLegacySharedAccountTestUtil sampleMSAJSONDictionary]; + + MSALLegacySharedMSAAccount *account = [[MSALLegacySharedMSAAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + MSALAccountEnumerationParameters *params = [[MSALAccountEnumerationParameters alloc] initWithIdentifier:@"oid.utid2"]; + params.returnOnlySignedInAccounts = NO; + BOOL result = [account matchesParameters:params]; + XCTAssertFalse(result); +} + +#pragma mark - Update + +- (void)testUpdateWithMSALAccount_whenUsernameAndSigninStatusChanged_shouldUpdateUsername +{ + NSString *appIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + NSMutableDictionary *jsonDictionary = [[MSALLegacySharedAccountTestUtil sampleMSAJSONDictionary] mutableCopy]; + NSDictionary *signinStatusDict = @{appIdentifier : @"SignedOut"}; + jsonDictionary[@"signInStatus"] = signinStatusDict; + jsonDictionary[@"email"] = @"old@contoso.old.com"; + + MSALLegacySharedMSAAccount *account = [[MSALLegacySharedMSAAccount alloc] initWithJSONDictionary:jsonDictionary error:nil]; + + NSError *updateError = nil; + BOOL result = [account updateAccountWithMSALAccount:[MSALLegacySharedAccountTestUtil testMSAAccount] + applicationName:@"MyApp" + operation:MSALLegacySharedAccountUpdateOperation + accountVersion:MSALLegacySharedAccountVersionV3 + error:&updateError]; + + XCTAssertTrue(result); + XCTAssertNil(updateError); + XCTAssertNotEqualObjects([account jsonDictionary], jsonDictionary); + NSString *newSigninStatus = [account jsonDictionary][@"signInStatus"][appIdentifier]; + XCTAssertEqualObjects(newSigninStatus, @"SignedIn"); + NSString *updatedByStatus = [account jsonDictionary][@"additionalProperties"][@"updatedBy"]; + XCTAssertEqualObjects(updatedByStatus, @"MyApp"); + NSString *updatedAt = [account jsonDictionary][@"additionalProperties"][@"updatedAt"]; + XCTAssertNotNil(updatedAt); + XCTAssertEqualObjects(account.accountType, @"MSA"); + XCTAssertEqualObjects(account.username, @"user@contoso.com"); + XCTAssertEqualObjects([account jsonDictionary][@"additionalfield1"], @"additionalvalue1"); + +} + +@end diff --git a/MSAL/test/unit/ios/external-cache/NSStringAccountIdentifiersTest.m b/MSAL/test/unit/ios/external-cache/NSStringAccountIdentifiersTest.m new file mode 100644 index 0000000000..1c6d643b1e --- /dev/null +++ b/MSAL/test/unit/ios/external-cache/NSStringAccountIdentifiersTest.m @@ -0,0 +1,178 @@ +//------------------------------------------------------------------------------ +// +// 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 "NSString+MSALAccountIdenfiers.h" + +@interface NSStringAccountIdentifiersTest : XCTestCase + +@end + +@implementation NSStringAccountIdentifiersTest + +#pragma mark - msalStringAsGUID + +- (void)testMsalStringAsGUID_whenLongerThan16CharsString_shouldReturnNil +{ + NSString *mylongString = @"12345678910111213141516"; + NSString *guid = [mylongString msalStringAsGUID]; + XCTAssertNil(guid); +} + +- (void)testMsalStringAsGUID_when16CharsString_shouldReturnGUIDData +{ + NSString *mylongString = @"40c03bac188d01d1"; + NSString *expectedUUID = @"00000000-0000-0000-40C0-3BAC188D01D1"; + + NSString *actualUUID = [mylongString msalStringAsGUID]; + XCTAssertNotNil(actualUUID); + XCTAssertEqualObjects(expectedUUID.lowercaseString, actualUUID); +} + +- (void)testMsalStringAsGUID_when8CharsString_shouldReturnGUIDData +{ + NSString *mylongString = @"188d01d1"; + + NSString *actualUUID = [mylongString msalStringAsGUID]; + XCTAssertNil(actualUUID); +} + +- (void)testMsalStringAsGUID_whenOddCharsString_shouldReturnGUIDData +{ + NSString *mylongString = @"188d01d"; + + NSString *actualUUID = [mylongString msalStringAsGUID]; + XCTAssertNil(actualUUID); +} + +- (void)testMsalStringAsGUID_whenEmptyCharsString_shouldReturnGUIDDataFilledWithZeroes +{ + NSString *myEmptyString = @""; + NSString *actualUUID = [myEmptyString msalStringAsGUID]; + XCTAssertNil(actualUUID); +} + +#pragma mark - msalStringAsGUIDData + +- (void)testMSALStringASGUIDData_whenLongerThan16CharsString_shouldReturnNil +{ + NSString *mylongString = @"12345678910111213141516"; + NSData *guidData = [mylongString msalStringAsGUIDData]; + XCTAssertNil(guidData); +} + +- (void)testMSALStringAsGUIDData_when16CharsString_shouldReturnGUIDData +{ + NSString *mylongString = @"40c03bac188d01d1"; + NSString *expectedUUID = @"00000000-0000-0000-40C0-3BAC188D01D1"; + + NSData *guidData = [mylongString msalStringAsGUIDData]; + XCTAssertNotNil(guidData); + NSUUID *actualUUID = [[NSUUID alloc] initWithUUIDBytes:[guidData bytes]]; + XCTAssertNotNil(actualUUID); + XCTAssertEqualObjects(expectedUUID, actualUUID.UUIDString); +} + +- (void)testMSALStringAsGUIDData_when8CharsString_shouldReturnGUIDData +{ + NSString *mylongString = @"188d01d1"; + NSString *expectedUUID = @"00000000-0000-0000-0000-0000188D01D1"; + + NSData *guidData = [mylongString msalStringAsGUIDData]; + XCTAssertNotNil(guidData); + NSUUID *actualUUID = [[NSUUID alloc] initWithUUIDBytes:[guidData bytes]]; + XCTAssertNotNil(actualUUID); + XCTAssertEqualObjects(expectedUUID, actualUUID.UUIDString); +} + +- (void)testMSALStringAsGUIDData_whenOddCharsString_shouldReturnGUIDData +{ + NSString *mylongString = @"188d01d"; + NSString *expectedUUID = @"00000000-0000-0000-0000-00000188D01D"; + + NSData *guidData = [mylongString msalStringAsGUIDData]; + XCTAssertNotNil(guidData); + NSUUID *actualUUID = [[NSUUID alloc] initWithUUIDBytes:[guidData bytes]]; + XCTAssertNotNil(actualUUID); + XCTAssertEqualObjects(expectedUUID, actualUUID.UUIDString); +} + +- (void)testMSALStringAsGUIDData_whenEmptyCharsString_shouldReturnGUIDDataFilledWithZeroes +{ + NSString *myEmptyString = @""; + NSString *expectedUUID = @"00000000-0000-0000-0000-000000000000"; + NSData *guidData = [myEmptyString msalStringAsGUIDData]; + XCTAssertNotNil(guidData); + NSUUID *actualUUID = [[NSUUID alloc] initWithUUIDBytes:[guidData bytes]]; + XCTAssertNotNil(actualUUID); + XCTAssertEqualObjects(expectedUUID, actualUUID.UUIDString); +} + +#pragma mark - msalGUIDAsShortString + +- (void)testMSALGUIDAsShortString_whenIncorrectGUID_shouldReturnNil +{ + NSString *input = @"xxkidkddndnjdj"; + NSString *output = [input msalGUIDAsShortString]; + XCTAssertNil(output); +} + +- (void)testMSALGUIDAsShortString_whenEmptyGUID_shouldReturnNil +{ + NSString *input = @""; + NSString *output = [input msalGUIDAsShortString]; + XCTAssertNil(output); +} + +- (void)testMSALGUIDAsShortString_whenOddCharsString_shouldReturnCorrectString +{ + NSString *expectedResult = @"188d01d"; + NSString *input = @"00000000-0000-0000-0000-00000188D01D"; + + NSString *result = [input msalGUIDAsShortString]; + XCTAssertEqualObjects(result, expectedResult); +} + +- (void)testMSALGUIDAsShortString_when16CharsString_shouldReturnCorrectString +{ + NSString *expectedResult = @"40c03bac188d01d1"; + NSString *input = @"00000000-0000-0000-40C0-3BAC188D01D1"; + + NSString *result = [input msalGUIDAsShortString]; + XCTAssertEqualObjects(result, expectedResult); +} + +- (void)testMSALGUIDAsShortString_when8CharsString_shouldReturnCorrectString +{ + NSString *expectedResult = @"188d01d1"; + NSString *input = @"00000000-0000-0000-0000-0000188D01D1"; + + NSString *result = [input msalGUIDAsShortString]; + XCTAssertEqualObjects(result, expectedResult); +} + +@end diff --git a/MSAL/test/app/mac/MSALTestAppDelegate.h b/MSAL/test/unit/mac/unit-test-host/AppDelegate.h similarity index 95% rename from MSAL/test/app/mac/MSALTestAppDelegate.h rename to MSAL/test/unit/mac/unit-test-host/AppDelegate.h index 47c49a2e12..6f8858f3ba 100644 --- a/MSAL/test/app/mac/MSALTestAppDelegate.h +++ b/MSAL/test/unit/mac/unit-test-host/AppDelegate.h @@ -27,7 +27,7 @@ #import -@interface MSALTestAppDelegate : NSObject +@interface AppDelegate : NSObject @end diff --git a/MSAL/test/app/mac/MSALTestAppDelegate.m b/MSAL/test/unit/mac/unit-test-host/AppDelegate.m similarity index 88% rename from MSAL/test/app/mac/MSALTestAppDelegate.m rename to MSAL/test/unit/mac/unit-test-host/AppDelegate.m index 4f4a1ae037..99fec7e59b 100644 --- a/MSAL/test/app/mac/MSALTestAppDelegate.m +++ b/MSAL/test/unit/mac/unit-test-host/AppDelegate.m @@ -25,26 +25,21 @@ // //------------------------------------------------------------------------------ -#import "MSALTestAppDelegate.h" +#import "AppDelegate.h" -@interface MSALTestAppDelegate () +@interface AppDelegate () -@property (weak) IBOutlet NSWindow *window; @end -@implementation MSALTestAppDelegate +@implementation AppDelegate -- (void)applicationDidFinishLaunching:(NSNotification *)aNotification -{ +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // Insert code here to initialize your application - (void)aNotification; } -- (void)applicationWillTerminate:(NSNotification *)aNotification -{ +- (void)applicationWillTerminate:(NSNotification *)aNotification { // Insert code here to tear down your application - (void)aNotification; } diff --git a/MSAL/test/unit/mac/unit-test-host/Assets.xcassets/AppIcon.appiconset/Contents.json b/MSAL/test/unit/mac/unit-test-host/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..2db2b1c7c6 --- /dev/null +++ b/MSAL/test/unit/mac/unit-test-host/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,58 @@ +{ + "images" : [ + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MSAL/test/unit/mac/unit-test-host/Assets.xcassets/Contents.json b/MSAL/test/unit/mac/unit-test-host/Assets.xcassets/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/MSAL/test/unit/mac/unit-test-host/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MSAL/test/unit/mac/unit-test-host/Base.lproj/Main.storyboard b/MSAL/test/unit/mac/unit-test-host/Base.lproj/Main.storyboard new file mode 100644 index 0000000000..fe3c53ef8d --- /dev/null +++ b/MSAL/test/unit/mac/unit-test-host/Base.lproj/Main.storyboard @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MSAL/test/unit/mac/unit-test-host/Info.plist b/MSAL/test/unit/mac/unit-test-host/Info.plist new file mode 100644 index 0000000000..f358448e86 --- /dev/null +++ b/MSAL/test/unit/mac/unit-test-host/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + Copyright © 2019 Microsoft. All rights reserved. + NSMainStoryboardFile + Main + NSPrincipalClass + NSApplication + + diff --git a/MSAL/test/unit/mac/unit-test-host/ViewController.h b/MSAL/test/unit/mac/unit-test-host/ViewController.h new file mode 100644 index 0000000000..f2c3d11aac --- /dev/null +++ b/MSAL/test/unit/mac/unit-test-host/ViewController.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 + +@interface ViewController : NSViewController + + +@end + diff --git a/MSAL/test/unit/mac/unit-test-host/ViewController.m b/MSAL/test/unit/mac/unit-test-host/ViewController.m new file mode 100644 index 0000000000..386442cf24 --- /dev/null +++ b/MSAL/test/unit/mac/unit-test-host/ViewController.m @@ -0,0 +1,46 @@ +//------------------------------------------------------------------------------ +// +// 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 "ViewController.h" + +@implementation ViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + // Do any additional setup after loading the view. +} + + +- (void)setRepresentedObject:(id)representedObject { + [super setRepresentedObject:representedObject]; + + // Update the view, if already loaded. +} + + +@end diff --git a/MSAL/test/unit/mac/unit-test-host/main.m b/MSAL/test/unit/mac/unit-test-host/main.m new file mode 100644 index 0000000000..8cd46b3f2c --- /dev/null +++ b/MSAL/test/unit/mac/unit-test-host/main.m @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// +// 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 + +int main(int argc, const char * argv[]) { + return NSApplicationMain(argc, argv); +} diff --git a/MSAL/src/public/configuration/publicClientApplication/MSALCacheConfig.h b/MSAL/test/unit/mocks/MSALMockExternalAccountHandler.h similarity index 75% rename from MSAL/src/public/configuration/publicClientApplication/MSALCacheConfig.h rename to MSAL/test/unit/mocks/MSALMockExternalAccountHandler.h index 7c519f6d63..391b0aedbb 100644 --- a/MSAL/src/public/configuration/publicClientApplication/MSALCacheConfig.h +++ b/MSAL/test/unit/mocks/MSALMockExternalAccountHandler.h @@ -26,21 +26,21 @@ //------------------------------------------------------------------------------ #import +#import "MSALExternalAccountHandler.h" NS_ASSUME_NONNULL_BEGIN -@interface MSALCacheConfig : NSObject +@interface MSALMockExternalAccountHandler : MSALExternalAccountHandler -/*! - The keychain sharing group to use for the token cache. - The default value is com.microsoft.adalcache. - */ -@property NSString *keychainSharingGroup; +@property (nonatomic) NSUInteger updateInvokedCount; +@property (nonatomic) NSUInteger removeAccountCount; +@property (nonatomic) NSUInteger allExternalAccountsInvokedCount; -- (nonnull instancetype)init NS_UNAVAILABLE; -+ (nonnull instancetype)new NS_UNAVAILABLE; +@property (nonatomic) NSError *accountOperationError; +@property (nonatomic) BOOL accountOperationResult; +@property (nonatomic) NSArray *externalAccountsResult; -+ (NSString *)defaultKeychainSharingGroup; +- (instancetype)initMock; @end diff --git a/MSAL/src/instance/MSALOauth2FactoryProducer.m b/MSAL/test/unit/mocks/MSALMockExternalAccountHandler.m similarity index 57% rename from MSAL/src/instance/MSALOauth2FactoryProducer.m rename to MSAL/test/unit/mocks/MSALMockExternalAccountHandler.m index 50009b985f..d358ff99f1 100644 --- a/MSAL/src/instance/MSALOauth2FactoryProducer.m +++ b/MSAL/test/unit/mocks/MSALMockExternalAccountHandler.m @@ -25,34 +25,53 @@ // //------------------------------------------------------------------------------ -#import "MSALOauth2FactoryProducer.h" -#import "MSIDOauth2Factory.h" -#import "MSIDB2CAuthority.h" -#import "MSIDAADAuthority.h" -#import "MSIDAADV2Oauth2Factory.h" -#import "MSIDB2COauth2Factory.h" +#import "MSALMockExternalAccountHandler.h" -@implementation MSALOauth2FactoryProducer +@implementation MSALMockExternalAccountHandler -+ (MSIDOauth2Factory *)msidOauth2FactoryForAuthority:(NSURL *)authority - context:(id)context - error:(NSError **)error +- (instancetype)initMock { - if (!authority) - { - MSIDFillAndLogError(error, MSIDErrorInvalidDeveloperParameter, @"Provided authority url is nil.", nil); + return [super init]; +} - return nil; +- (BOOL)updateWithResult:(MSALResult *)result error:(NSError * _Nullable * _Nullable)error +{ + self.updateInvokedCount++; + + if (self.accountOperationError) + { + if (error) + { + *error = self.accountOperationError; + } + + return NO; } + + return self.accountOperationResult; +} - if ([MSIDB2CAuthority isAuthorityFormatValid:authority context:context error:nil]) +- (BOOL)removeAccount:(MSALAccount *)account error:(NSError * _Nullable * _Nullable)error +{ + self.removeAccountCount++; + + if (self.accountOperationError) { - return [MSIDB2COauth2Factory new]; + if (error) + { + *error = self.accountOperationError; + } + + return NO; } + + return self.accountOperationResult; +} - // Create AAD v2 factory for everything else, but in future we might want to further separate this out - // (e.g. ADFS, Google, Oauth2 etc...) - return [MSIDAADV2Oauth2Factory new]; +- (nullable NSArray *)allExternalAccountsWithParameters:(MSALAccountEnumerationParameters *)parameters error:(NSError **)error +{ + self.allExternalAccountsInvokedCount++; + return self.externalAccountsResult; } @end diff --git a/MSAL/test/unit/telemetry/MSALTelemetryDispatcherTests.m b/MSAL/test/unit/telemetry/MSALTelemetryDispatcherTests.m deleted file mode 100644 index 249c0647fb..0000000000 --- a/MSAL/test/unit/telemetry/MSALTelemetryDispatcherTests.m +++ /dev/null @@ -1,273 +0,0 @@ -//------------------------------------------------------------------------------ -// -// 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 "MSALTestCase.h" -#import "MSALTelemetryTestDispatcher.h" -#import "MSALTelemetry.h" -#import "MSIDTelemetry+Internal.h" -#import "MSIDTelemetryHttpEvent.h" -#import "MSIDTelemetryEventStrings.h" -#import "MSIDTelemetryAPIEvent.h" - -#import "MSALTelemetryConfig+Internal.h" - -@interface MSALTestRequestContext : NSObject -{ - NSString *_requestId; - NSUUID *_correlationId; -} - -- (instancetype)initWithTelemetryRequestId:(NSString *)requestId correlationId:(NSUUID *)correlationId; - -@end - -@implementation MSALTestRequestContext - -- (instancetype)initWithTelemetryRequestId:(NSString *)requestId correlationId:(NSUUID *)correlationId -{ - if (!(self = [super init])) - { - return nil; - } - - _requestId = requestId; - _correlationId = correlationId; - - return self; -} - -- (NSUUID *)correlationId -{ - return _correlationId; -} - -- (NSString *)telemetryRequestId -{ - return _requestId; -} - -- (NSString *)logComponent -{ - return nil; -} - -- (NSDictionary *)appRequestMetadata -{ - return nil; -} - -- (NSURLSession *)urlSession -{ - return nil; -} - -@end - -@interface MSALTelemetryDispatcherTests : MSALTestCase - -@end - -@implementation MSALTelemetryDispatcherTests - -- (void)setUp -{ - [super setUp]; - // Put setup code here. This method is called before the invocation of each test method in the class. -} - -- (void)tearDown -{ - // Put teardown code here. This method is called after the invocation of each test method in the class. - [super tearDown]; -} - -- (void)testDispatcherEmpty -{ - MSALTelemetryTestDispatcher* dispatcher = [MSALTelemetryTestDispatcher new]; - - __block NSArray *> *receivedEvents = nil; - - [dispatcher setDispatcherCallback:^(NSArray *> *event) - { - receivedEvents = event; - }]; - - [MSALTelemetryConfig.sharedInstance addDispatcher:dispatcher setTelemetryOnFailure:NO]; - - NSString *requestId = [[MSIDTelemetry sharedInstance] generateRequestId]; - - // Flush without adding any additional events - [[MSIDTelemetry sharedInstance] flush:requestId]; - - // Verify that default event is not added in such case - XCTAssertEqual([receivedEvents count], 0); -} - -- (void)testDispatcherAll -{ - MSALTelemetryConfig.sharedInstance.piiEnabled = YES; - MSALTelemetryTestDispatcher* dispatcher = [MSALTelemetryTestDispatcher new]; - - __block NSArray *> *receivedEvents = nil; - - [MSALTelemetryConfig.sharedInstance addDispatcher:dispatcher setTelemetryOnFailure:NO]; - - [dispatcher setDispatcherCallback:^(NSArray *> *event) - { - receivedEvents = event; - }]; - - NSString* requestId = [[MSIDTelemetry sharedInstance] generateRequestId]; - NSUUID* correlationId = [NSUUID UUID]; - id ctx = [[MSALTestRequestContext alloc] initWithTelemetryRequestId:requestId - correlationId:correlationId]; - - // API event - [[MSIDTelemetry sharedInstance] startEvent:requestId eventName:@"apiEvent"]; - MSIDTelemetryAPIEvent *apiEvent = [[MSIDTelemetryAPIEvent alloc] initWithName:@"apiEvent" context:ctx]; - [apiEvent setProperty:@"api_property" value:@"api_value"]; - [apiEvent setCorrelationId:correlationId]; - [[MSIDTelemetry sharedInstance] stopEvent:requestId event:apiEvent]; - - // HTTP event - [[MSIDTelemetry sharedInstance] startEvent:requestId eventName:@"httpEvent"]; - - [[MSIDTelemetry sharedInstance] stopEvent:requestId - event:[[MSIDTelemetryHttpEvent alloc] initWithName:@"httpEvent" context:ctx]]; - - [[MSIDTelemetry sharedInstance] flush:requestId]; - - // Verify results: there should be 3 events (default, HTTP, API) - XCTAssertEqual([receivedEvents count], 3); - - // Default event - NSDictionary *defaultEventProperties = [receivedEvents objectAtIndex:0]; - NSArray *defaultEventPropertyNames = [defaultEventProperties allKeys]; - XCTAssertEqual([defaultEventPropertyNames count], 9); - XCTAssertTrue([defaultEventPropertyNames containsObject:@"msal.application_name"]); - XCTAssertTrue([defaultEventPropertyNames containsObject:@"msal.application_version"]); - XCTAssertTrue([defaultEventPropertyNames containsObject:@"msal.device_id"]); - XCTAssertTrue([defaultEventPropertyNames containsObject:@"msal.event_name"]); - XCTAssertTrue([defaultEventPropertyNames containsObject:@"msal.x_client_cpu"]); - XCTAssertTrue([defaultEventPropertyNames containsObject:@"msal.x_client_dm"]); - XCTAssertTrue([defaultEventPropertyNames containsObject:@"msal.x_client_os"]); - XCTAssertTrue([defaultEventPropertyNames containsObject:@"msal.x_client_sku"]); - XCTAssertTrue([defaultEventPropertyNames containsObject:@"msal.x_client_ver"]); - - XCTAssertTrue([[defaultEventProperties objectForKey:@"msal.event_name"] compare:@"default_event" - options:NSCaseInsensitiveSearch] == NSOrderedSame); - - // API event - NSDictionary *apiEventProperties = [receivedEvents objectAtIndex:1]; - NSArray *apiEventPropertyNames = [apiEventProperties allKeys]; - XCTAssertTrue([apiEventPropertyNames containsObject:@"msal.start_time"]); - XCTAssertTrue([apiEventPropertyNames containsObject:@"msal.stop_time"]); - XCTAssertTrue([apiEventPropertyNames containsObject:@"msal.correlation_id"]); - XCTAssertTrue([apiEventPropertyNames containsObject:@"msal.response_time"]); - XCTAssertTrue([apiEventPropertyNames containsObject:@"msal.request_id"]); - - XCTAssertTrue([[apiEventProperties objectForKey:@"msal.event_name"] compare:@"apiEvent" - options:NSCaseInsensitiveSearch] == NSOrderedSame); - XCTAssertTrue([[apiEventProperties objectForKey:@"api_property"] compare:@"api_value" - options:NSCaseInsensitiveSearch] == NSOrderedSame); - - // HTTP event - NSDictionary *httpEventProperties = [receivedEvents objectAtIndex:2]; - NSArray *httpEventPropertyNames = [httpEventProperties allKeys]; - XCTAssertTrue([httpEventPropertyNames containsObject:@"msal.start_time"]); - XCTAssertTrue([httpEventPropertyNames containsObject:@"msal.stop_time"]); - XCTAssertTrue([httpEventPropertyNames containsObject:@"msal.response_time"]); - - XCTAssertTrue([[httpEventProperties objectForKey:@"msal.event_name"] compare:@"httpEvent" - options:NSCaseInsensitiveSearch] == NSOrderedSame); -} - -- (void)testDispatcherErrorOnlyWithError -{ - MSALTelemetryTestDispatcher* dispatcher = [MSALTelemetryTestDispatcher new]; - - __block NSArray *> *receivedEvents = nil; - - [MSALTelemetryConfig.sharedInstance addDispatcher:dispatcher setTelemetryOnFailure:YES]; - - [dispatcher setDispatcherCallback:^(NSArray *> *event) - { - receivedEvents = event; - }]; - - NSString* requestId = [[MSIDTelemetry sharedInstance] generateRequestId]; - NSUUID* correlationId = [NSUUID UUID]; - id ctx = [[MSALTestRequestContext alloc] initWithTelemetryRequestId:requestId - correlationId:correlationId]; - - // HTTP event - [[MSIDTelemetry sharedInstance] startEvent:requestId eventName:@"httpEvent"]; - MSIDTelemetryHttpEvent *httpEvent = [[MSIDTelemetryHttpEvent alloc] initWithName:@"httpEvent" context:ctx]; - [httpEvent setHttpErrorCode:@"error_code_123"]; - [[MSIDTelemetry sharedInstance] stopEvent:requestId event:httpEvent]; - - [[MSIDTelemetry sharedInstance] flush:requestId]; - - // Verify results - XCTAssertEqual([receivedEvents count], 2); - - NSString *errorCode = [[receivedEvents objectAtIndex:1] objectForKey:TELEMETRY_KEY(MSID_TELEMETRY_KEY_HTTP_RESPONSE_CODE)]; - - XCTAssertNotNil(errorCode); - XCTAssertTrue([errorCode compare:@"error_code_123" options:NSCaseInsensitiveSearch] == NSOrderedSame); -} - -- (void)testDispatcherErrorOnlyWithoutError -{ - MSALTelemetryTestDispatcher* dispatcher = [MSALTelemetryTestDispatcher new]; - - __block NSArray *> *receivedEvents = nil; - - [MSALTelemetryConfig.sharedInstance addDispatcher:dispatcher setTelemetryOnFailure:YES]; - - [dispatcher setDispatcherCallback:^(NSArray *> *event) - { - receivedEvents = event; - }]; - - NSString* requestId = [[MSIDTelemetry sharedInstance] generateRequestId]; - NSUUID* correlationId = [NSUUID UUID]; - id ctx = [[MSALTestRequestContext alloc] initWithTelemetryRequestId:requestId - correlationId:correlationId]; - - // HTTP event - [[MSIDTelemetry sharedInstance] startEvent:requestId eventName:@"httpEvent"]; - MSIDTelemetryHttpEvent *httpEvent = [[MSIDTelemetryHttpEvent alloc] initWithName:@"httpEvent" context:ctx]; - [[MSIDTelemetry sharedInstance] stopEvent:requestId event:httpEvent]; - - [[MSIDTelemetry sharedInstance] flush:requestId]; - - // Verify results - XCTAssertNil(receivedEvents); -} - -@end diff --git a/MSAL/test/unit/utils/MSALTestConstants.h b/MSAL/test/unit/utils/MSALTestConstants.h index 87818764bb..82567a9050 100644 --- a/MSAL/test/unit/utils/MSALTestConstants.h +++ b/MSAL/test/unit/utils/MSALTestConstants.h @@ -39,6 +39,12 @@ #define UNIT_TEST_DEFAULT_REDIRECT_SCHEME @"msal"UNIT_TEST_CLIENT_ID // Unit test redirect uri : msal://auth +#if TARGET_OS_IPHONE #define UNIT_TEST_DEFAULT_REDIRECT_URI UNIT_TEST_DEFAULT_REDIRECT_SCHEME"://auth" +#else +#define UNIT_TEST_DEFAULT_REDIRECT_URI @"msauth.com.microsoft.unit-test-host://auth" +#endif + +#define UNIT_TEST_DEFAULT_BUNDLE_ID @"com.microsoft.mytest.bundleId" #define UT_SLICE_PARAMS_QUERY diff --git a/MSAL/test/unit/utils/MSIDTestURLResponse+MSAL.h b/MSAL/test/unit/utils/MSIDTestURLResponse+MSAL.h index 1095c968ab..ab4cbdbf79 100644 --- a/MSAL/test/unit/utils/MSIDTestURLResponse+MSAL.h +++ b/MSAL/test/unit/utils/MSIDTestURLResponse+MSAL.h @@ -40,8 +40,9 @@ + (MSIDTestURLResponse *)rtResponseForScopes:(NSOrderedSet *)scopes authority:(NSString *)authority tenantId:(NSString *)tid + uid:(NSString *)uid user:(MSALAccount *)user - claims:(NSString *)decodedClaims; + claims:(NSString *)claims; + (MSIDTestURLResponse *)errorRtResponseForScopes:(NSOrderedSet *)scopes authority:(NSString *)authority diff --git a/MSAL/test/unit/utils/MSIDTestURLResponse+MSAL.m b/MSAL/test/unit/utils/MSIDTestURLResponse+MSAL.m index 6aa7d7bbb7..2b06053c5e 100644 --- a/MSAL/test/unit/utils/MSIDTestURLResponse+MSAL.m +++ b/MSAL/test/unit/utils/MSIDTestURLResponse+MSAL.m @@ -146,6 +146,7 @@ + (MSIDTestURLResponse *)oidcResponseForAuthority:(NSString *)authority + (MSIDTestURLResponse *)rtResponseForScopes:(NSOrderedSet *)scopes authority:(NSString *)authority tenantId:(NSString *)tid + uid:(NSString *)uid user:(MSALAccount *)user claims:(NSString *)claims { @@ -170,9 +171,10 @@ + (MSIDTestURLResponse *)rtResponseForScopes:(NSOrderedSet *)scopes @"refresh_token" : @"i am a refresh token", @"id_token" : [MSIDTestIdTokenUtil idTokenWithName:@"Test name" preferredUsername:user.username - tenantId:tid ? tid : user.homeAccountId.objectId], + oid:nil + tenantId:tid], @"id_token_expires_in" : @"1200", - @"client_info" : [@{ @"uid" : user.homeAccountId.objectId, @"utid" : user.homeAccountId.tenantId} msidBase64UrlJson], + @"client_info" : [@{ @"uid" : uid, @"utid" : tid} msidBase64UrlJson], @"scope": [scopes msidToString] } ]; diff --git a/README.md b/README.md index 0fe4a7c001..df80aa0142 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Microsoft Authentication Library Preview for iOS +Microsoft Authentication Library Preview for iOS and macOS ===================================== | [Get Started](https://docs.microsoft.com/azure/active-directory/develop/quickstart-v2-ios) | [Sample Code](https://github.com/Azure-Samples/active-directory-ios-swift-native-v2) | [Support](README.md#community-help-and-support) @@ -6,7 +6,7 @@ Microsoft Authentication Library Preview for iOS The MSAL library preview gives your app the ability to begin using the [Microsoft Identity platform](https://aka.ms/aaddev) by supporting [Azure Active Directory](https://azure.microsoft.com/en-us/services/active-directory/) and [Microsoft Accounts](https://account.microsoft.com) in a converged experience using industry standard OAuth2 and OpenID Connect. The library also supports [Azure AD B2C](https://azure.microsoft.com/services/active-directory-b2c/) for those using our hosted identity management service. -Note that for the preview, **only iOS is supported.** macOS support will be provided in a future realse. Need it sooner? Let us know! +Note that throughout the preview, only iOS has been supported. Starting with **MSAL release 0.5.0**, MSAL now supports macOS. ## Important Note about the MSAL Preview @@ -34,7 +34,7 @@ These libraries are suitable to use in a production environment. We provide the let accessToken = authResult.accessToken // You'll want to get the account identifier to retrieve and reuse the account for later acquireToken calls - let accountIdentifier = authResult.account.homeAccountId?.identifier + let accountIdentifier = authResult.account.identifier }) } else { @@ -58,7 +58,7 @@ These libraries are suitable to use in a production environment. We provide the { // You'll want to get the account identifier to retrieve and reuse the account // for later acquireToken calls - NSString *accountIdentifier = result.account.homeAccountId.identifier; + NSString *accountIdentifier = result.account.identifier; NSString *accessToken = result.accessToken; } @@ -99,7 +99,13 @@ You can also use Git Submodule or check out the latest release and use as framew ### Adding MSAL to your project 1. Register your app in the [Azure portal](https://aka.ms/MobileAppReg) -2. Add your application's redirect URI scheme to your `Info.plist` file, it will be in the format of `msauth.[BUNDLE_ID]` +2. Make sure you register a redirect URI for your application. It should be in the following format: + + `msauth.[BUNDLE_ID]://auth` + +####iOS only steps: + +1. Add your application's redirect URI scheme to your `Info.plist` file, it will be in the format of `msauth.[BUNDLE_ID]` ```xml CFBundleURLTypes @@ -111,7 +117,8 @@ You can also use Git Submodule or check out the latest release and use as framew ``` -3. Add `LSApplicationQueriesSchemes` to allow making call to Microsoft Authenticator if installed. +2. Add `LSApplicationQueriesSchemes` to allow making call to Microsoft Authenticator if installed. + ```xml LSApplicationQueriesSchemes @@ -121,11 +128,11 @@ You can also use Git Submodule or check out the latest release and use as framew ``` See more info about configuring redirect uri for MSAL in our [Wiki](https://github.com/AzureAD/microsoft-authentication-library-for-objc/wiki/Redirect-uris-in-MSAL) -4. Add a new keychain group to your project Capabilities `com.microsoft.adalcache` . See more information about keychain groups for MSAL in our [Wiki](https://github.com/AzureAD/microsoft-authentication-library-for-objc/wiki/Keychain-on-iOS) +3. Add a new keychain group to your project Capabilities `com.microsoft.adalcache` . See more information about keychain groups for MSAL in our [Wiki](https://github.com/AzureAD/microsoft-authentication-library-for-objc/wiki/Keychain-on-iOS) ![](Images/keychain_example.png) -5. To handle a callback, add the following to `appDelegate`: +4. To handle a callback, add the following to `appDelegate`: Swift ```swift @@ -150,6 +157,10 @@ Objective-C } ``` +#### macOS only steps: + +1. Make sure your application is signed with a valid development certificate. While MSAL will still work in the unsigned mode, it will behave differently around cache persistence. + ## Using MSAL ### Creating an Application Object @@ -168,7 +179,7 @@ NSError *msalError; MSALPublicClientApplicationConfig *config = [[MSALPublicClientApplicationConfig alloc] initWithClientId:@""]; MSALPublicClientApplication *application = [[MSALPublicClientApplication alloc] initWithConfiguration:config error:&msalError]; -``` +``` ### Acquiring Your First Token Swift ```swift @@ -184,7 +195,7 @@ Swift let accessToken = authResult.accessToken // You'll want to get the account identifier to retrieve and reuse the account for later acquireToken calls - let accountIdentifier = authResult.account.homeAccountId?.identifier + let accountIdentifier = authResult.account.identifier }) ``` Objective-C @@ -195,7 +206,7 @@ Objective-C { // You'll want to get the account identifier to retrieve and reuse the account // for later acquireToken calls - NSString *accountIdentifier = result.account.homeAccountId.identifier; + NSString *accountIdentifier = result.account.identifier; NSString *accessToken = result.accessToken; } @@ -210,7 +221,7 @@ Objective-C ### Silently Acquiring an Updated Token Swift ```swift -guard let account = try? application.account(forHomeAccountId: accountIdentifier) else { return } +guard let account = try? application.account(forIdentifier: accountIdentifier) else { return } let silentParameters = MSALSilentTokenParameters(scopes: scopes, account: account) application.acquireTokenSilent(with: silentParameters) { (result, error) in @@ -234,7 +245,7 @@ guard let account = try? application.account(forHomeAccountId: accountIdentifier Objective-C ```objective-c NSError *error = nil; - MSALAccount *account = [application accountForHomeAccountId:accountIdentifier error:&error]; + MSALAccount *account = [application accountForIdentifier:accountIdentifier error:&error]; if (!account) { // handle error