diff --git a/ADAL.podspec b/ADAL.podspec index 4fbbc2686..ba80b8115 100644 --- a/ADAL.podspec +++ b/ADAL.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "ADAL" s.module_name = "ADAL" - s.version = "2.7.8" + s.version = "2.7.9" s.summary = "The ADAL SDK for iOS gives you the ability to add Azure Identity authentication to your application" s.description = <<-DESC diff --git a/ADAL/resources/ios/Framework/Info.plist b/ADAL/resources/ios/Framework/Info.plist index e998d0697..911df6ec1 100644 --- a/ADAL/resources/ios/Framework/Info.plist +++ b/ADAL/resources/ios/Framework/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.7.8 + 2.7.9 CFBundleSignature ???? CFBundleVersion diff --git a/ADAL/resources/mac/Info.plist b/ADAL/resources/mac/Info.plist index c280a3c30..1c2978e30 100644 --- a/ADAL/resources/mac/Info.plist +++ b/ADAL/resources/mac/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.7.8 + 2.7.9 CFBundleSignature ???? CFBundleVersion diff --git a/ADAL/src/ADAL_Internal.h b/ADAL/src/ADAL_Internal.h index bc4b3b3a2..63ee4eeb1 100644 --- a/ADAL/src/ADAL_Internal.h +++ b/ADAL/src/ADAL_Internal.h @@ -27,7 +27,7 @@ // through build script. Don't change its format unless changing build script as well.) #define ADAL_VER_HIGH 2 #define ADAL_VER_LOW 7 -#define ADAL_VER_PATCH 8 +#define ADAL_VER_PATCH 9 #define STR_HELPER(x) #x #define STR(x) STR_HELPER(x) diff --git a/ADAL/src/workplacejoin/ADPkeyAuthHelper.m b/ADAL/src/workplacejoin/ADPkeyAuthHelper.m index 84edbf663..dd968b515 100644 --- a/ADAL/src/workplacejoin/ADPkeyAuthHelper.m +++ b/ADAL/src/workplacejoin/ADPkeyAuthHelper.m @@ -71,8 +71,7 @@ + (nullable NSString*)createDeviceAuthResponse:(nonnull NSString*)authorizationS { ADAuthenticationError* adError = nil; ADRegistrationInformation *info = - [ADWorkPlaceJoinUtil getRegistrationInformation:context - error:&adError]; + [ADWorkPlaceJoinUtil getRegistrationInformation:context urlChallenge:nil error:&adError]; if (!info && adError) { diff --git a/ADAL/src/workplacejoin/ADWorkPlaceJoinUtil.h b/ADAL/src/workplacejoin/ADWorkPlaceJoinUtil.h index 39b356e90..652c7ad81 100644 --- a/ADAL/src/workplacejoin/ADWorkPlaceJoinUtil.h +++ b/ADAL/src/workplacejoin/ADWorkPlaceJoinUtil.h @@ -27,7 +27,8 @@ @interface ADWorkPlaceJoinUtil : NSObject -+ (ADRegistrationInformation*)getRegistrationInformation:(id)context - error:(ADAuthenticationError * __autoreleasing *)error; ++ (ADRegistrationInformation *)getRegistrationInformation:(id)context + urlChallenge:(NSURLAuthenticationChallenge *)challenge + error:(ADAuthenticationError * __autoreleasing *)error; @end diff --git a/ADAL/src/workplacejoin/ios/ADWorkPlaceJoinUtil.m b/ADAL/src/workplacejoin/ios/ADWorkPlaceJoinUtil.m index 657724e33..cae94dd68 100644 --- a/ADAL/src/workplacejoin/ios/ADWorkPlaceJoinUtil.m +++ b/ADAL/src/workplacejoin/ios/ADWorkPlaceJoinUtil.m @@ -51,8 +51,9 @@ @implementation ADWorkPlaceJoinUtil } -+ (ADRegistrationInformation*)getRegistrationInformation:(id)context - error:(ADAuthenticationError * __autoreleasing *)error ++ (ADRegistrationInformation *)getRegistrationInformation:(id)context + urlChallenge:(NSURLAuthenticationChallenge *)challenge + error:(ADAuthenticationError * __autoreleasing *)error { NSString* teamId = [ADKeychainUtil keychainTeamId:error]; diff --git a/ADAL/src/workplacejoin/mac/ADClientCertAuthHandler.m b/ADAL/src/workplacejoin/mac/ADClientCertAuthHandler.m index 31b4714bc..227a3c137 100644 --- a/ADAL/src/workplacejoin/mac/ADClientCertAuthHandler.m +++ b/ADAL/src/workplacejoin/mac/ADClientCertAuthHandler.m @@ -54,10 +54,9 @@ + (void)resetHandler + (BOOL)isWPJChallenge:(NSArray *)distinguishedNames { - for (NSData *distinguishedName in distinguishedNames) { - NSString *distinguishedNameString = [[[NSString alloc] initWithData:distinguishedName encoding:NSISOLatin1StringEncoding] lowercaseString]; + NSString *distinguishedNameString = [[[NSString alloc] initWithData:distinguishedName encoding:NSASCIIStringEncoding] lowercaseString]; if ([distinguishedNameString containsString:[kADALProtectionSpaceDistinguishedName lowercaseString]]) { return YES; @@ -72,7 +71,7 @@ + (BOOL)handleWPJChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(ChallengeCompletionHandler)completionHandler { ADAuthenticationError *adError = nil; - ADRegistrationInformation *info = [ADWorkPlaceJoinUtil getRegistrationInformation:protocol.context error:&adError]; + ADRegistrationInformation *info = [ADWorkPlaceJoinUtil getRegistrationInformation:protocol.context urlChallenge:challenge error:&adError]; if (!info || ![info isWorkPlaceJoined]) { MSID_LOG_INFO(protocol.context, @"Device is not workplace joined"); diff --git a/ADAL/src/workplacejoin/mac/ADWorkPlaceJoinUtil.m b/ADAL/src/workplacejoin/mac/ADWorkPlaceJoinUtil.m index 273d84077..388131a82 100644 --- a/ADAL/src/workplacejoin/mac/ADWorkPlaceJoinUtil.m +++ b/ADAL/src/workplacejoin/mac/ADWorkPlaceJoinUtil.m @@ -37,11 +37,10 @@ } \ } -static const UInt8 certificateIdentifier[] = "WorkPlaceJoin-Access\0"; - @implementation ADWorkPlaceJoinUtil + (ADRegistrationInformation *)getRegistrationInformation:(id)context + urlChallenge:(NSURLAuthenticationChallenge *)challenge error:(ADAuthenticationError * __autoreleasing *)error { ADRegistrationInformation *info = nil; @@ -51,58 +50,50 @@ + (ADRegistrationInformation *)getRegistrationInformation:(id)context + issuer:(NSString **)issuer + certificateAuthorities:(NSArray *)authorities -+ (void)copyCertificate:(SecCertificateRef __nullable * __nonnull)certificate - identity:(SecIdentityRef __nullable * __nonnull)identity - issuer:(NSString * __nullable * __nonnull)issuer - context:(id)context - error:(ADAuthenticationError * __nullable __autoreleasing * __nullable)error { - OSStatus status = noErr; - ADAuthenticationError *adError = nil; - NSData *issuerData = nil; - NSDictionary *identityQuery = nil; - CFDictionaryRef result = NULL; - - *identity = nil; - *certificate = nil; - if (error) - { - *error = nil; - } - - *certificate = [self copyWPJCertificateRef:context error:&adError]; - - if (adError) - { - if (error) - { - *error = adError; - } - - MSID_LOG_ERROR(context, @"Failed to retrieve WPJ client certificate from keychain. Error code: %ld", (long)adError.code); - goto _error; - } - - // If there's no certificate in the keychain, adError won't be set since this isn't an error condition. - if (!*certificate) + if (![authorities count]) { - return; + return NULL; } - // In OS X the shared access group cannot be set, so the search needs to be more - // specific. The code below searches the identity by passing the WPJ cert as reference. - identityQuery = @{ (__bridge id)kSecClass : (__bridge id)kSecClassIdentity, - (__bridge id)kSecReturnRef : (__bridge id)kCFBooleanTrue, - (__bridge id)kSecReturnAttributes : (__bridge id)kCFBooleanTrue, - (__bridge id)kSecAttrKeyClass : (__bridge id)kSecAttrKeyClassPrivate, - (__bridge id)kSecValueRef : (__bridge id)*certificate - }; + NSDictionary *query = @{ (__bridge id)kSecClass : (__bridge id)kSecClassIdentity, + (__bridge id)kSecReturnAttributes:(__bridge id)kCFBooleanTrue, + (__bridge id)kSecReturnRef : (__bridge id)kCFBooleanTrue, + (__bridge id)kSecMatchLimit : (__bridge id)kSecMatchLimitAll, + (__bridge id)kSecMatchIssuers : authorities + }; - status = SecItemCopyMatching((__bridge CFDictionaryRef)identityQuery, (CFTypeRef*)&result); - CHECK_KEYCHAIN_STATUS(@"Failed to retrieve WPJ identity from keychain."); + CFArrayRef identityList = NULL; + SecIdentityRef identityRef = NULL; + NSDictionary *identityDict = nil; + NSData *currentIssuer = nil; + NSString *currentIssuerName = nil; - issuerData = [(__bridge NSDictionary*)result objectForKey:(__bridge id)kSecAttrIssuer]; - if (issuerData) - { - *issuer = [[NSString alloc] initWithData:issuerData encoding:NSISOLatin1StringEncoding]; - } + OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&identityList); - *identity = (__bridge SecIdentityRef)([(__bridge NSDictionary*)result objectForKey:(__bridge id)kSecValueRef]); - if (*identity) + if (status != errSecSuccess) { - CFRetain(*identity); + return NULL; } - CFRelease(result); - - return; + CFIndex identityCount = CFArrayGetCount(identityList); + NSString *challengeIssuerName = [[NSString alloc] initWithData:authorities[0] encoding:NSASCIIStringEncoding]; -_error: - - if (*identity) + for (int resultIndex = 0; resultIndex < identityCount; resultIndex++) { - CFRelease(*identity); + identityDict = (NSDictionary *)CFArrayGetValueAtIndex(identityList, resultIndex); + + if ([identityDict isKindOfClass:[NSDictionary class]]) + { + currentIssuer = [identityDict objectForKey:(__bridge NSString*)kSecAttrIssuer]; + currentIssuerName = [[NSString alloc] initWithData:currentIssuer encoding:NSASCIIStringEncoding]; + + /* The issuer name returned from the certificate in keychain is capitalized but the issuer name returned from the TLS challenge is not. + Hence we need to do a caseInsenstitive compare to match the issuer. + */ + if ([challengeIssuerName caseInsensitiveCompare:currentIssuerName] == NSOrderedSame) + { + identityRef = (__bridge_retained SecIdentityRef)[identityDict objectForKey:(__bridge NSString*)kSecValueRef]; + + if (issuer) + { + *issuer = currentIssuerName; + } + + break; + } + } } - *identity = nil; - if (*certificate) + if (identityList) { - CFRelease(*certificate); + CFRelease(identityList); + identityList = NULL; } - *certificate = nil; - *issuer = nil; -} - - -+ (SecCertificateRef)copyWPJCertificateRef:(id)context - error:(ADAuthenticationError * __nullable __autoreleasing * __nullable)error -{ - OSStatus status= noErr; - SecCertificateRef certRef = NULL; - NSData *issuerTag = [self wpjCertIssuerTag]; - - // Set the private key query dictionary. - NSDictionary *queryCert = @{ (__bridge id)kSecClass : (__bridge id)kSecClassCertificate, - (__bridge id)kSecAttrLabel : issuerTag - }; - - // Get the certificate. If the certificate is not found, this is not considered an error. - status = SecItemCopyMatching((__bridge CFDictionaryRef)queryCert, (CFTypeRef*)&certRef); - if (status == errSecItemNotFound) - { - return NULL; - } - - CHECK_KEYCHAIN_STATUS(@"Failed to read WPJ certificate."); - - return certRef; - -_error: - return NULL; -} - -+ (NSData *)wpjCertIssuerTag -{ - return [NSData dataWithBytes:certificateIdentifier length:strlen((const char *)certificateIdentifier)]; -} - -+ (SecKeyRef)copyPrivateKeyRefForIdentifier:(NSString *)identifier - context:(id)context - error:(ADAuthenticationError* __nullable __autoreleasing * __nullable)error -{ - OSStatus status= noErr; - SecKeyRef privateKeyReference = NULL; - - NSData *privateKeyTag = [NSData dataWithBytes:[identifier UTF8String] length:identifier.length]; - - // Set the private key query dictionary. - NSDictionary *privateKeyQuery = @{ (__bridge id)kSecClass : (__bridge id)kSecClassKey, - (__bridge id)kSecAttrApplicationTag : privateKeyTag, - (__bridge id)kSecAttrKeyType : (__bridge id)kSecAttrKeyTypeRSA, - (__bridge id)kSecReturnRef : (__bridge id)kCFBooleanTrue - }; - - // Get the key. - status = SecItemCopyMatching((__bridge CFDictionaryRef)privateKeyQuery, (CFTypeRef*)&privateKeyReference); - CHECK_KEYCHAIN_STATUS(@"Failed to read WPJ private key for identifier."); - - return privateKeyReference; - -_error: - return nil; + return identityRef; //Caller must call CFRelease } @end diff --git a/ADAL/tests/app/src/ios/ADTestAppSettingsViewController.m b/ADAL/tests/app/src/ios/ADTestAppSettingsViewController.m index e555511c2..56090b7b9 100644 --- a/ADAL/tests/app/src/ios/ADTestAppSettingsViewController.m +++ b/ADAL/tests/app/src/ios/ADTestAppSettingsViewController.m @@ -136,7 +136,7 @@ - (void)viewDidLoad - (void)viewWillAppear:(BOOL)animated { ADRegistrationInformation* regInfo = - [ADWorkPlaceJoinUtil getRegistrationInformation:nil error:nil]; + [ADWorkPlaceJoinUtil getRegistrationInformation:nil urlChallenge:nil error:nil]; NSString* wpjLabel = @"No WPJ Registration Found"; diff --git a/changelog.txt b/changelog.txt index 0960c1d44..a4ab5557e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +Version 2.7.9 (03.06.2018) +----------- +* Hotfix for Mac OS to query WPJ cert using issuers from authentication challenge. + Version 2.7.8 ----------- * Hotfix to skip user Id matching check for an acquire token silent call.