Skip to content

Commit

Permalink
Merge pull request #1391 from AzureAD/hotfix/2.7.9
Browse files Browse the repository at this point in the history
create hot fix branch 2.7.9
  • Loading branch information
rohitnarula7176 authored Mar 19, 2019
2 parents e6871db + 09e2735 commit 70fa45c
Show file tree
Hide file tree
Showing 11 changed files with 94 additions and 171 deletions.
2 changes: 1 addition & 1 deletion ADAL.podspec
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion ADAL/resources/ios/Framework/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.7.8</string>
<string>2.7.9</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
Expand Down
2 changes: 1 addition & 1 deletion ADAL/resources/mac/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.7.8</string>
<string>2.7.9</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
Expand Down
2 changes: 1 addition & 1 deletion ADAL/src/ADAL_Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 1 addition & 2 deletions ADAL/src/workplacejoin/ADPkeyAuthHelper.m
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
5 changes: 3 additions & 2 deletions ADAL/src/workplacejoin/ADWorkPlaceJoinUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@

@interface ADWorkPlaceJoinUtil : NSObject

+ (ADRegistrationInformation*)getRegistrationInformation:(id<MSIDRequestContext>)context
error:(ADAuthenticationError * __autoreleasing *)error;
+ (ADRegistrationInformation *)getRegistrationInformation:(id<MSIDRequestContext>)context
urlChallenge:(NSURLAuthenticationChallenge *)challenge
error:(ADAuthenticationError * __autoreleasing *)error;

@end
5 changes: 3 additions & 2 deletions ADAL/src/workplacejoin/ios/ADWorkPlaceJoinUtil.m
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ @implementation ADWorkPlaceJoinUtil
}


+ (ADRegistrationInformation*)getRegistrationInformation:(id<MSIDRequestContext>)context
error:(ADAuthenticationError * __autoreleasing *)error
+ (ADRegistrationInformation *)getRegistrationInformation:(id<MSIDRequestContext>)context
urlChallenge:(NSURLAuthenticationChallenge *)challenge
error:(ADAuthenticationError * __autoreleasing *)error
{
NSString* teamId = [ADKeychainUtil keychainTeamId:error];

Expand Down
5 changes: 2 additions & 3 deletions ADAL/src/workplacejoin/mac/ADClientCertAuthHandler.m
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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");
Expand Down
233 changes: 76 additions & 157 deletions ADAL/src/workplacejoin/mac/ADWorkPlaceJoinUtil.m
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,10 @@
} \
}

static const UInt8 certificateIdentifier[] = "WorkPlaceJoin-Access\0";

@implementation ADWorkPlaceJoinUtil

+ (ADRegistrationInformation *)getRegistrationInformation:(id<MSIDRequestContext>)context
urlChallenge:(NSURLAuthenticationChallenge *)challenge
error:(ADAuthenticationError * __autoreleasing *)error
{
ADRegistrationInformation *info = nil;
Expand All @@ -51,58 +50,50 @@ + (ADRegistrationInformation *)getRegistrationInformation:(id<MSIDRequestContext
NSString *certificateSubject = nil;
NSData *certificateData = nil;
NSString *certificateIssuer = nil;
ADAuthenticationError *adError = nil;

if (error)
{
*error = nil;
}
OSStatus status = noErr;

MSID_LOG_VERBOSE(context, @"Attempting to get WPJ registration information");
identity = [self copyWPJIdentity:context issuer:&certificateIssuer certificateAuthorities:challenge.protectionSpace.distinguishedNames];

[self copyCertificate:&certificate identity:&identity issuer:&certificateIssuer context:context error:&adError];
if (adError)
// If there's no identity in the keychain, return nil. adError won't be set if the
// identity can't be found since this isn't considered an error condition.
if (!identity || CFGetTypeID(identity) != SecIdentityGetTypeID())
{
if (error)
MSID_LOG_VERBOSE(context, @"Failed to retrieve WPJ identity.");
if (identity)
{
*error = adError;
CFRelease(identity);
identity = NULL;
}
MSID_LOG_ERROR(context, @"Failed to retrieve WPJ certificate. Error code: %ld", (long)adError.code);
goto _error;

return NULL;
}

// If there's no certificate in the keychain, return nil. adError won't be set if the
// cert can't be found since this isn't considered an error condition.
if (!certificate)
{
return nil;
}
// Get the wpj certificate
MSID_LOG_VERBOSE(context, @"Retrieving WPJ certificate reference.");
status = SecIdentityCopyCertificate(identity, &certificate);
CHECK_KEYCHAIN_STATUS(@"Failed to read WPJ certificate.");

certificateSubject = (__bridge_transfer NSString*)(SecCertificateCopySubjectSummary(certificate));
certificateData = (__bridge_transfer NSData*)(SecCertificateCopyData(certificate));

// Get the private key
MSID_LOG_VERBOSE(context, @"Retrieving WPJ private key reference.");
status = SecIdentityCopyPrivateKey(identity, &privateKey);
CHECK_KEYCHAIN_STATUS(@"Failed to read WPJ private key for identifier.");

privateKey = [self copyPrivateKeyRefForIdentifier:kADALPrivateKeyIdentifier context:context error:&adError];
if (adError)
{
if (error)
{
*error = adError;
}
MSID_LOG_ERROR(context, @"Failed to retrieve WPJ private key reference. Error code %ld", (long)adError.code);
goto _error;
}

if (!identity || !certificateIssuer || !certificateSubject || !certificateData || !privateKey)
if (!certificate || !certificateIssuer || !certificateSubject || !certificateData || !privateKey)
{
// The code above will catch missing security items, but not missing item attributes. These are caught here.
ADAuthenticationError* adError = [ADAuthenticationError unexpectedInternalError:@"Missing some piece of WPJ data" correlationId:context.correlationId];
if (error)
{
// The code above will catch missing security items, but not missing item attributes. These are caught here.
ADAuthenticationError* adError =
[ADAuthenticationError unexpectedInternalError:@"Missing some piece of WPJ data"
correlationId:context.correlationId];

*error = adError;
}

goto _error;
}

Expand All @@ -121,160 +112,88 @@ + (ADRegistrationInformation *)getRegistrationInformation:(id<MSIDRequestContext
if (identity)
{
CFRelease(identity);
identity = NULL;
}
if (certificate)
{
CFRelease(certificate);
certificate = NULL;
}
if (privateKey)
{
CFRelease(privateKey);
privateKey = NULL;
}

return info;
}

+ (SecIdentityRef)copyWPJIdentity:(id<MSIDRequestContext>)context
issuer:(NSString **)issuer
certificateAuthorities:(NSArray<NSData *> *)authorities

+ (void)copyCertificate:(SecCertificateRef __nullable * __nonnull)certificate
identity:(SecIdentityRef __nullable * __nonnull)identity
issuer:(NSString * __nullable * __nonnull)issuer
context:(id<MSIDRequestContext>)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<MSIDRequestContext>)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<MSIDRequestContext>)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
Expand Down
Loading

0 comments on commit 70fa45c

Please sign in to comment.