diff --git a/Classes/BITAuthenticator.m b/Classes/BITAuthenticator.m index 1a9fc47e8f..645e894f9f 100644 --- a/Classes/BITAuthenticator.m +++ b/Classes/BITAuthenticator.m @@ -36,6 +36,7 @@ #import "BITHockeyHelper.h" static NSString* const kBITAuthenticatorAuthTokenKey = @"BITAuthenticatorAuthTokenKey"; +static NSString* const kBITAuthenticatorAuthTokenTypeKey = @"BITAuthenticatorAuthTokenTypeKey"; static NSString* const kBITAuthenticatorAuthTokenVendorIdentifierKey = @"BITAuthenticatorAuthTokenVendorIdentifierKey"; static NSString* const kBITAuthenticatorLastAuthenticatedVersionKey = @"BITAuthenticatorLastAuthenticatedVersionKey"; static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticatorDidSkipOptionalLogin"; @@ -101,6 +102,15 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato return bit_appAnonID(); } +- (NSString*) installationIdentificationType { + NSString *authToken = self.authenticationToken; + if(nil == authToken) { + return @"udid"; + } else { + return [self authenticationTokenType]; + } +} + #pragma mark - Validation - (void) validateInstallationWithCompletion:(tValidationCompletion) completion { if(nil == self.authenticationToken) { @@ -146,19 +156,8 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato - (NSDictionary*) validationParameters { NSParameterAssert(self.authenticationToken); - NSDictionary *params = nil; - switch (self.authenticationType) { - case BITAuthenticatorAuthTypeEmail: - params = @{@"iuid" : self.authenticationToken}; - break; - case BITAuthenticatorAuthTypeEmailAndPassword: - params = @{@"auid" : self.authenticationToken}; - break; - case BITAuthenticatorAuthTypeUDIDProvider: - params = @{@"udid" : self.authenticationToken}; - break; - } - return params; + NSParameterAssert(self.installationIdentificationType); + return @{self.installationIdentificationType : self.authenticationToken}; } + (BOOL) isValidationResponseValid:(id) response error:(NSError **) error { @@ -269,7 +268,7 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato - (void) didAuthenticateWithToken:(NSString*) token { [_authenticationController dismissModalViewControllerAnimated:YES]; _authenticationController = nil; - self.authenticationToken = token; + [self setAuthenticationToken:token withType:[self.class stringForAuthenticationType:self.authenticationType]]; self.installationIdentificationValidated = YES; self.lastAuthenticatedVersion = [self executableUUID]; if(self.authenticationCompletionBlock) { @@ -277,12 +276,24 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato self.authenticationCompletionBlock = nil; } } + ++ (NSString*) stringForAuthenticationType:(BITAuthenticatorAuthType) authType { + switch (authType) { + case BITAuthenticatorAuthTypeEmail: return @"iuid"; + case BITAuthenticatorAuthTypeEmailAndPassword: return @"auid"; + case BITAuthenticatorAuthTypeUDIDProvider: + //fallthrough + default: + return @"udid"; + break; + } +} #pragma mark - AuthenticationViewControllerDelegate - (void) authenticationViewControllerDidSkip:(UIViewController *)viewController { [viewController dismissModalViewControllerAnimated:YES]; _authenticationController = nil; - self.authenticationToken = nil; + [self setAuthenticationToken:nil withType:nil]; if(self.validationType == BITAuthenticatorValidationTypeOptional) { self.didSkipOptionalLogin = YES; } @@ -439,7 +450,7 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato [self didAuthenticateWithToken:udid]; } else { //reset auth-token - self.authenticationToken = nil; + [self setAuthenticationToken:nil withType:nil]; if(self.validationType == BITAuthenticatorValidationTypeOptional) { //dismiss view-controller if login was optional @@ -499,6 +510,7 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato - (void) cleanupInternalStorage { [self removeKeyFromKeychain:kBITAuthenticatorAuthTokenKey]; + [self removeKeyFromKeychain:kBITAuthenticatorAuthTokenTypeKey]; [self removeKeyFromKeychain:kBITAuthenticatorAuthTokenVendorIdentifierKey]; [self removeKeyFromKeychain:kBITAuthenticatorDidSkipOptionalLogin]; [self setLastAuthenticatedVersion:nil]; @@ -538,14 +550,16 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato } #pragma mark - Property overrides -- (void)setAuthenticationToken:(NSString *)authenticationToken { +- (void)setAuthenticationToken:(NSString *)authenticationToken withType:(NSString*) authenticationTokenType { + NSParameterAssert(nil == authenticationToken || nil != authenticationTokenType); if(![self.authenticationToken isEqualToString:authenticationToken]) { [self willChangeValueForKey:@"installationIdentification"]; if(nil == authenticationToken) { [self removeKeyFromKeychain:kBITAuthenticatorAuthTokenKey]; - [self removeKeyFromKeychain:kBITAuthenticatorAuthTokenVendorIdentifierKey]; + [self removeKeyFromKeychain:kBITAuthenticatorAuthTokenTypeKey]; } else { [self addStringValueToKeychain:authenticationToken forKey:kBITAuthenticatorAuthTokenKey]; + [self addStringValueToKeychain:authenticationTokenType forKey:kBITAuthenticatorAuthTokenTypeKey]; NSString *identifierForVendor = self.currentDevice.identifierForVendor.UUIDString; [self addStringValueToKeychain:identifierForVendor forKey:kBITAuthenticatorAuthTokenVendorIdentifierKey]; } @@ -568,6 +582,11 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato return authToken; } +- (NSString *)authenticationTokenType { + NSString *authTokenType = [self stringValueFromKeychainForKey:kBITAuthenticatorAuthTokenTypeKey]; + return authTokenType; +} + - (void)setLastAuthenticatedVersion:(NSString *)lastAuthenticatedVersion { NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; if(nil == lastAuthenticatedVersion){ diff --git a/Classes/BITAuthenticator_Private.h b/Classes/BITAuthenticator_Private.h index 7108fe94ff..667e6192e0 100644 --- a/Classes/BITAuthenticator_Private.h +++ b/Classes/BITAuthenticator_Private.h @@ -50,7 +50,13 @@ * This is retrieved from the hockeyApp backend * @see installationIdentifier */ -@property (nonatomic, copy) NSString *authenticationToken; +@property (nonatomic, readonly) NSString *authenticationToken; + +/** + * store the authentication token with the given type + * if authToken is not nil, authentikationTokenType must also be non nil + */ +- (void)setAuthenticationToken:(NSString *)authenticationToken withType:(NSString*) authenticationTokenType; /** * holds the identifier of the last version that was authenticated @@ -62,10 +68,8 @@ /** * Specifies the type of installation identification for the current app installation - * - * KVO'able */ -@property (nonatomic, readonly) BOOL installationIdentificationType; +@property (nonatomic, readonly) NSString *installationIdentificationType; /** * removes all previously stored authentication tokens, UDIDs, etc diff --git a/Support/HockeySDKTests/BITAuthenticatorTests.m b/Support/HockeySDKTests/BITAuthenticatorTests.m index f97add3d4e..07f75a971b 100644 --- a/Support/HockeySDKTests/BITAuthenticatorTests.m +++ b/Support/HockeySDKTests/BITAuthenticatorTests.m @@ -84,7 +84,7 @@ static void *kInstallationIdentification = &kInstallationIdentification; #pragma mark - Persistence Tests - (void) testThatAuthenticationTokenIsPersisted { - _sut.authenticationToken = @"SuperToken"; + [_sut setAuthenticationToken:@"SuperToken" withType:@"udid"]; _sut = [[BITAuthenticator alloc] initWithAppIdentifier:nil isAppStoreEnvironemt:YES]; assertThat(_sut.authenticationToken, equalTo(@"SuperToken")); } @@ -96,13 +96,15 @@ static void *kInstallationIdentification = &kInstallationIdentification; } - (void) testThatCleanupWorks { - _sut.authenticationToken = @"MyToken"; + [_sut setAuthenticationToken:@"MyToken" withType:@"udid"]; _sut.lastAuthenticatedVersion = @"1.2"; [_sut cleanupInternalStorage]; assertThat(_sut.authenticationToken, equalTo(nil)); assertThat(_sut.lastAuthenticatedVersion, equalTo(nil)); + assertThat(_sut.installationIdentificationType, equalTo(@"udid")); + assertThatBool(_sut.didSkipOptionalLogin, equalToBool(NO)); } - (void) testThatSkipLoginIsPersisted { @@ -121,7 +123,7 @@ static void *kInstallationIdentification = &kInstallationIdentification; } - (void) testIdentificationReturnsTheAuthTokenIfSet { - _sut.authenticationToken = @"PeterPan"; + [_sut setAuthenticationToken:@"PeterPan" withType:@"udid"]; assertThat(_sut.installationIdentification, equalTo(@"PeterPan")); } @@ -186,7 +188,7 @@ static void *kInstallationIdentification = &kInstallationIdentification; - (void) testThatSuccessfulAuthenticationCallsTheBlock { id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate)); _sut.delegate = delegateMock; - _sut.authenticationToken = @"Test"; + [_sut setAuthenticationToken:@"Test" withType:@"adid"]; __block BOOL didAuthenticate = NO; [_sut authenticateWithCompletion:^(NSString *authenticationToken, NSError *error) { if(authenticationToken) didAuthenticate = YES; @@ -220,7 +222,7 @@ static void *kInstallationIdentification = &kInstallationIdentification; - (void) testThatCancelledAuthenticationResetsTheToken { id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate)); _sut.delegate = delegateMock; - _sut.authenticationToken = @"Meh"; + [_sut setAuthenticationToken:@"Meh" withType:@"bdid"]; //this will prepare everything and show the viewcontroller [_sut authenticateWithCompletion:nil]; @@ -252,6 +254,38 @@ static void *kInstallationIdentification = &kInstallationIdentification; } } +#pragma mark - InstallationIdentificationType +- (void) testThatEmailAuthSetsTheProperInstallationIdentificationType { + _sut.authenticationType = BITAuthenticatorAuthTypeEmail; + //fake delegate call from the viewcontroller + [_sut didAuthenticateWithToken:@"SuperToken"]; + + assertThat(_sut.installationIdentificationType, equalTo(@"iuid")); +} + +- (void) testThatPasswordAuthSetsTheProperInstallationIdentificationType { + _sut.authenticationType = BITAuthenticatorAuthTypeEmailAndPassword; + //fake delegate call from the viewcontroller + [_sut didAuthenticateWithToken:@"SuperToken"]; + + assertThat(_sut.installationIdentificationType, equalTo(@"auid")); +} + +- (void) testThatUDIDAuthSetsTheProperInstallationIdentificationType { + _sut.authenticationType = BITAuthenticatorAuthTypeUDIDProvider; + //fake delegate call from the viewcontroller + [_sut didAuthenticateWithToken:@"SuperToken"]; + + assertThat(_sut.installationIdentificationType, equalTo(@"udid")); +} + +- (void) testThatDefaultAuthReturnsProperInstallationIdentificationType { + _sut.authenticationType = BITAuthenticatorAuthTypeEmailAndPassword; + //fake delegate call from the viewcontroller + [_sut authenticationViewControllerDidSkip:nil]; + + assertThat(_sut.installationIdentificationType, equalTo(@"udid")); +} #pragma mark - validation tests - (void) testThatValidationWithoutTokenWantsToShowTheAuthenticationViewController { id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));