From a06367b2f8c946892b9406ebafaba1ffd3992fb9 Mon Sep 17 00:00:00 2001 From: Kaylie Son Date: Tue, 21 Nov 2017 11:22:24 -0800 Subject: [PATCH] DE328373 : [iOS][Multi-Server] MAS Set Security Configuration call gets success though setting Public Server and Trust Public PKI value set as 'False' --- MASFoundation/Classes/MASConstants.h | 6 + .../_private_/categories/NSError+MASPrivate.m | 6 + .../Classes/models/MASConfiguration.h | 27 ++++- .../Classes/models/MASConfiguration.m | 105 ++++++++++++++---- 4 files changed, 116 insertions(+), 28 deletions(-) diff --git a/MASFoundation/Classes/MASConstants.h b/MASFoundation/Classes/MASConstants.h index 2505b83e..2a4a86c6 100644 --- a/MASFoundation/Classes/MASConstants.h +++ b/MASFoundation/Classes/MASConstants.h @@ -329,6 +329,12 @@ typedef NS_ENUM(NSInteger, MASFoundationErrorCode) MASFoundationErrorCodeConfigurationLoadingFailedJsonValidation = 100203, MASFoundationErrorCodeConfigurationInvalidEndpoint = 100204, + // + // Security Configuration + // + MASFoundationErrorCodeConfigurationInvalidHostForSecurityConfiguration = 100211, + MASFoundationErrorCodeConfigurationInvalidPinningInfoForSecurityConfiguration = 100212, + // // Geolocation // diff --git a/MASFoundation/Classes/_private_/categories/NSError+MASPrivate.m b/MASFoundation/Classes/_private_/categories/NSError+MASPrivate.m index 51ecb6bc..1a3c0c90 100644 --- a/MASFoundation/Classes/_private_/categories/NSError+MASPrivate.m +++ b/MASFoundation/Classes/_private_/categories/NSError+MASPrivate.m @@ -984,6 +984,12 @@ + (NSString *)descriptionForFoundationErrorCode:(MASFoundationErrorCode)errorCod case MASFoundationErrorCodeConfigurationLoadingFailedJsonValidation: return @"The configuration was successfully loaded, but the configuration is invalid for the following reason\n\n'%@'"; case MASFoundationErrorCodeConfigurationInvalidEndpoint: return @"Invalid endpoint"; + // + // Security Configuration + // + case MASFoundationErrorCodeConfigurationInvalidHostForSecurityConfiguration: return @"Invalid host information for security configuration. NSURL host or port cannot be nil."; + case MASFoundationErrorCodeConfigurationInvalidPinningInfoForSecurityConfiguration: return @"Invalid pinning information for security configuration. At least one pinning information should be provided or public PKI should be trusted."; + // // Device // diff --git a/MASFoundation/Classes/models/MASConfiguration.h b/MASFoundation/Classes/models/MASConfiguration.h index 51d544be..8d4eafd8 100644 --- a/MASFoundation/Classes/models/MASConfiguration.h +++ b/MASFoundation/Classes/models/MASConfiguration.h @@ -174,13 +174,17 @@ # pragma mark - Security Configuration /** - Sets security measure for SSL pinning, and SSL validation for specified host in MASSecurityConfiguration object + Sets security measure for SSL pinning, and SSL validation for specified host in MASSecurityConfiguration object. + + @remark MASSecurityConfiguration must have valid host in NSURL object with port number (port number is mandatory), at least one pinning information (either certificates, or public key hashes), or trust public PKI. If public PKI is not trusted, and no pinning information is provided, it will fail to store the security configuration object, and eventually fail on evaluating SSL for requests. @warning Upon SDK initialization, [MASConfiguration currentConfiguration].gatewayUrl's MASSecurityConfiguration object will be overwritten. If primary gateway's security configuration has to be modified, ensure to set security configuration after SDK initialization. - @param securityConfiguration MASSecurityConfiguration object with host, and security measure configuration values. - */ -+ (void)setSecurityConfiguration:(MASSecurityConfiguration *_Nonnull)securityConfiguration; + @param securityConfiguration MASSecurityConfiguration object with host, and security measure configuration values + @param error NSError object reference to notify any error occurred while validating MASSecurityConfiguration + @return YES if security configuration was successfully set + */ ++ (BOOL)setSecurityConfiguration:(MASSecurityConfiguration *_Nonnull)securityConfiguration error:(NSError *__nullable __autoreleasing *__nullable)error; @@ -352,4 +356,19 @@ + (NSError *_Nullable)validateJSONConfiguration:(NSDictionary *_Nonnull)configuration; + +///-------------------------------------- +/// @name Deprecated +///-------------------------------------- + +# pragma mark - Deprecated + +/** + Sets security measure for SSL pinning, and SSL validation for specified host in MASSecurityConfiguration object + + @warning Upon SDK initialization, [MASConfiguration currentConfiguration].gatewayUrl's MASSecurityConfiguration object will be overwritten. If primary gateway's security configuration has to be modified, ensure to set security configuration after SDK initialization. + @param securityConfiguration MASSecurityConfiguration object with host, and security measure configuration values. + */ ++ (void)setSecurityConfiguration:(MASSecurityConfiguration *_Nonnull)securityConfiguration DEPRECATED_MSG_ATTRIBUTE("[MASConfiguration setSecurityConfiguration:] is deprecated. Use [MASConfiguration setSecurityConfiguration:error:] instead for better handling of error cases."); + @end diff --git a/MASFoundation/Classes/models/MASConfiguration.m b/MASFoundation/Classes/models/MASConfiguration.m index 268b55d7..d9705c15 100644 --- a/MASFoundation/Classes/models/MASConfiguration.m +++ b/MASFoundation/Classes/models/MASConfiguration.m @@ -201,7 +201,7 @@ - (id)init - (id)initPrivate { self = [super init]; - if(self) + if (self) { } @@ -212,7 +212,7 @@ - (id)initPrivate - (id)initWithConfigurationInfo:(NSDictionary *)info { - if(self = [super init]) + if (self = [super init]) { _configurationInfo_ = info; @@ -232,7 +232,10 @@ - (void)initializeEndpointsFromInfo:(NSDictionary *)info // // If the dictionary already exists ignore the call // - if(_endpointKeysToPaths) return; + if (_endpointKeysToPaths) + { + return; + } // // Create the dictionary @@ -243,15 +246,21 @@ - (void)initializeEndpointsFromInfo:(NSDictionary *)info // OAuth Endpoints // NSDictionary *oauthInfo = _configurationInfo_[MASOAuthConfigurationKey]; - if(oauthInfo) + if (oauthInfo) { // System Endpoints NSDictionary *endpointsInfo = oauthInfo[MASSystemEndpointsConfigurationKey]; - if(endpointsInfo) [_endpointKeysToPaths addEntriesFromDictionary:endpointsInfo]; + if (endpointsInfo) + { + [_endpointKeysToPaths addEntriesFromDictionary:endpointsInfo]; + } // Protected Endpoints endpointsInfo = oauthInfo[MASProtectedEndpointsConfigurationKey]; - if(endpointsInfo) [_endpointKeysToPaths addEntriesFromDictionary:endpointsInfo]; + if (endpointsInfo) + { + [_endpointKeysToPaths addEntriesFromDictionary:endpointsInfo]; + } } @@ -259,22 +268,28 @@ - (void)initializeEndpointsFromInfo:(NSDictionary *)info // MAG Endpoints // NSDictionary *magInfo = _configurationInfo_[MASMAGConfigurationKey]; - if(magInfo) + if (magInfo) { // System Endpoints NSDictionary *endpointsInfo = magInfo[MASSystemEndpointsConfigurationKey]; - if(endpointsInfo) [_endpointKeysToPaths addEntriesFromDictionary:endpointsInfo]; + if (endpointsInfo) + { + [_endpointKeysToPaths addEntriesFromDictionary:endpointsInfo]; + } // Protected Endpoints endpointsInfo = magInfo[MASProtectedEndpointsConfigurationKey]; - if(endpointsInfo) [_endpointKeysToPaths addEntriesFromDictionary:endpointsInfo]; + if (endpointsInfo) + { + [_endpointKeysToPaths addEntriesFromDictionary:endpointsInfo]; + } } // // MAS Endpoints // NSDictionary *masInfo = _configurationInfo_[MASConfigurationKey]; - if(masInfo) + if (masInfo) { // // currently scim-path is configured as String, maybe later when it comes as dictionary change it @@ -282,14 +297,14 @@ - (void)initializeEndpointsFromInfo:(NSDictionary *)info //scim-path NSString *scimPathInfo = masInfo[MASScimPathEndpoint]; - if(scimPathInfo) + if (scimPathInfo) { [_endpointKeysToPaths addEntriesFromDictionary:@{MASScimPathEndpoint : scimPathInfo}]; } //storage-path NSString *storagePathInfo = masInfo[MASStoragePathEndpoint]; - if(scimPathInfo) + if (scimPathInfo) { [_endpointKeysToPaths addEntriesFromDictionary:@{MASStoragePathEndpoint : storagePathInfo}]; } @@ -299,8 +314,10 @@ - (void)initializeEndpointsFromInfo:(NSDictionary *)info // Custom Endpoints // NSDictionary *customInfo = _configurationInfo_[MASCustomConfigurationKey]; - if(customInfo) [_endpointKeysToPaths addEntriesFromDictionary:customInfo]; - + if (customInfo) + { + [_endpointKeysToPaths addEntriesFromDictionary:customInfo]; + } // // Temporary Hardcoded Endpoints @@ -322,7 +339,7 @@ + (MASConfiguration *)instanceFromStorage // Attempt to retrieve from keychain // NSData *data = [[MASIKeyChainStore keyChainStoreWithService:[MASConfiguration currentConfiguration].gatewayUrl.absoluteString] dataForKey:[MASConfiguration.class description]]; - if(data) + if (data) { configuration = (MASConfiguration *)[NSKeyedUnarchiver unarchiveObjectWithData:data]; } @@ -337,11 +354,11 @@ - (void)saveToStorage // Save to the keychain // NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self]; - if(data) + if (data) { NSError *error; [[MASIKeyChainStore keyChainStoreWithService:[MASConfiguration currentConfiguration].gatewayUrl.absoluteString] setData:data forKey:[MASConfiguration.class description] error:&error]; - if(error) + if (error) { DLog(@"Error attempting to save data: %@", [error localizedDescription]); } @@ -365,13 +382,16 @@ - (void)encodeWithCoder:(NSCoder *)aCoder MASKeyChainService *keyChainService = [MASKeyChainService keyChainService]; // Configuration - if(_configurationInfo_) [keyChainService setConfiguration:_configurationInfo_]; + if (_configurationInfo_) + { + [keyChainService setConfiguration:_configurationInfo_]; + } } - (id)initWithCoder:(NSCoder *)aDecoder { - if(self = [super init]) + if (self = [super init]) { MASKeyChainService *keyChainService = [MASKeyChainService keyChainService]; @@ -386,9 +406,38 @@ - (id)initWithCoder:(NSCoder *)aDecoder } -+ (void)setSecurityConfiguration:(MASSecurityConfiguration *)securityConfiguration ++ (BOOL)setSecurityConfiguration:(MASSecurityConfiguration *)securityConfiguration error:(NSError **)error { + // + // Validate the NSURL host for security configuration. + // + if (!securityConfiguration.host || !securityConfiguration.host.port) + { + if (error) + { + *error = [NSError errorForFoundationCode:MASFoundationErrorCodeConfigurationInvalidHostForSecurityConfiguration errorDomain:MASFoundationErrorDomainLocal]; + } + + return NO; + } + + // + // Validate pinning information for the security configuration. + // At least one pinning information (certificates or public key hashes) should be defined, or public PKI should be trusted. + // + if (!securityConfiguration.trustPublicPKI && (!securityConfiguration.certificates || [securityConfiguration.certificates count]== 0) && (!securityConfiguration.publicKeyHashes || [securityConfiguration.publicKeyHashes count] == 0)) + { + if (error) + { + *error = [NSError errorForFoundationCode:MASFoundationErrorCodeConfigurationInvalidPinningInfoForSecurityConfiguration errorDomain:MASFoundationErrorDomainLocal]; + } + + return NO; + } + [MASConfigurationService setSecurityConfiguration:securityConfiguration]; + + return YES; } @@ -553,7 +602,7 @@ - (NSString *)gatewayHostName error:nil]; NSUInteger numberOfMatches = [regexToValidateIP numberOfMatchesInString:gatewayInfo[MASGatewayHostNameKey] options:0 range:NSMakeRange(0, [gatewayInfo[MASGatewayHostNameKey] length])]; - if(_systemVersionNumber_ < 9.0 && numberOfMatches != 1) + if (_systemVersionNumber_ < 9.0 && numberOfMatches != 1) { if (![MASDevice currentDevice].isRegistered) { @@ -882,7 +931,7 @@ - (NSString *)debugDescription NSMutableString *endpoints = [[NSMutableString alloc] initWithString:@"\n\n {\n"]; NSString *keyToEndpoint; - for(NSString *endpointKey in _endpointKeysToPaths) + for (NSString *endpointKey in _endpointKeysToPaths) { keyToEndpoint = [NSString stringWithFormat:@" %@ = %@\n", endpointKey, _endpointKeysToPaths[endpointKey]]; [endpoints appendString:keyToEndpoint]; @@ -904,13 +953,13 @@ - (NSString *)debugDescription - (NSDictionary *)defaultApplicationClientInfo { NSMutableArray *applicationClientInfoFound = [NSMutableArray new]; - for(NSDictionary *info in self.applicationClients) + for (NSDictionary *info in self.applicationClients) { [applicationClientInfoFound addObject:info]; } // Should there be two or more allowed in the list that meet that criteria? Can it happen? - if(applicationClientInfoFound.count > 1) + if (applicationClientInfoFound.count > 1) { DLog(@"Warning: found %ld iOS clients that are enabled, just choosing first in the list", (long)applicationClientInfoFound.count); @@ -981,4 +1030,12 @@ - (NSArray *)generateCertificatesFromPEM:(NSArray *)certificatesAsPEM return certificatesAsDER; } + +# pragma mark - Deprecated + ++ (void)setSecurityConfiguration:(MASSecurityConfiguration *)securityConfiguration +{ + [self setSecurityConfiguration:securityConfiguration error:nil]; +} + @end