More authenticator integration

- Only start the updateManager if the installation is authenticated (not yet tested)
- Provide the installation data to the updateManager requests
- Some more documentation
- Authenticator defaults to BITAuthenticatorAuthTypeUDIDProvider and BITAuthenticatorValidationTypeNever
- Reset usage time if installation identification changes (not yet tested)
This commit is contained in:
Andreas Linde 2013-09-11 14:05:09 +02:00
parent d7dbb06666
commit d93da3ee32
8 changed files with 180 additions and 66 deletions

View File

@ -51,35 +51,48 @@ typedef void(^tValidationCompletion)(BOOL validated, NSError *error);
@protocol BITAuthenticatorDelegate; @protocol BITAuthenticatorDelegate;
/** /**
* Authenticator module used to identify and optionally authenticate the current * Authenticator module used to identify and optionally authenticate the current app installation
* app installation *
* This is the HockeySDK module for handling authentications when using Ad-Hoc or Enterprise provisioning profiles.
* This modul allows you to make sure the current app installation is done on an authorzied device by choosing from
* various authenticatoin and validation mechanisms which provide different levels of authentication.
*
* This does not provide DRM or copy protection in any form and each authentication type and validation type provide
* a different level of authentication.
*
* This module automatically disables itself when running in an App Store build by default!
* *
* Authentication is actually a 2 step process: * Authentication is actually a 2 step process:
* 1) authenticate * 1) authenticate
* some kind of token is aquired depending on the authenticationType * some kind of token is aquired depending on the authenticationType
* 2) verification * 2) validation
* the aquired token from step 1 is verified depending the validationType * the aquired token from step 1 is validated depending the validationType
* *
* There are currently 3 ways of authentication: * There are currently 3 ways of authentication:
* 1) authenticate the user via email only * 1) authenticate the user via email only (`BITAuthenticatorAuthTypeEmail`)
* 2) authenticate the user via email & passwort (needs to have a HockeyApp Account) * 2) authenticate the user via email & passwort (needs to have a HockeyApp Account) (`BITAuthenticatorAuthTypeEmailAndPassword`)
* 3) authenticate the device via its UDID * 3) authenticate the device via its UDID (_Default_) (`BITAuthenticatorAuthTypeUDIDProvider`)
* *
* Additionally, verification can be required: * Additionally, verification can be required:
* 1) never * 1) never (`BITAuthenticatorValidationTypeNever`)
* 2) optional * 2) optional (`BITAuthenticatorValidationTypeOptional`)
* 3) on first launch of every app version, never again until the next version is installed * 3) on first launch of every app version, never again until the next version is installed (_Default_) (`BITAuthenticatorValidationTypeOnFirstLaunch`)
* 4) every time the app becomes active (needs data connection) * 4) every time the app becomes active (needs data connection) (`BITAuthenticatorValidationTypeOnAppActive`)
* *
*/ */
@interface BITAuthenticator : BITHockeyBaseManager @interface BITAuthenticator : BITHockeyBaseManager
#pragma mark - Configuration #pragma mark - Configuration
/**
* Defines the authentication mechanism to be used
*
* _Default_: BITAuthenticatorAuthTypeUDIDProvider
*/
@property (nonatomic, assign) BITAuthenticatorAuthType authenticationType; @property (nonatomic, assign) BITAuthenticatorAuthType authenticationType;
/** /**
* defaults to BITAuthenticatorValidationTypeNever * _Default_: BITAuthenticatorValidationTypeNever
*/ */
@property (nonatomic, assign) BITAuthenticatorValidationType validationType; @property (nonatomic, assign) BITAuthenticatorValidationType validationType;

View File

@ -54,6 +54,9 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
self = [super initWithAppIdentifier:appIdentifier isAppStoreEnvironemt:isAppStoreEnvironment]; self = [super initWithAppIdentifier:appIdentifier isAppStoreEnvironemt:isAppStoreEnvironment];
if( self ) { if( self ) {
_webpageURL = [NSURL URLWithString:@"https://rink.hockeyapp.net/"]; _webpageURL = [NSURL URLWithString:@"https://rink.hockeyapp.net/"];
_authenticationType = BITAuthenticatorAuthTypeUDIDProvider;
_validationType = BITAuthenticatorValidationTypeNever;
} }
return self; return self;
} }

View File

@ -60,6 +60,13 @@
@property (nonatomic, copy) tAuthenticationCompletion authenticationCompletionBlock; @property (nonatomic, copy) tAuthenticationCompletion authenticationCompletionBlock;
/**
* Specifies the type of installation identification for the current app installation
*
* KVO'able
*/
@property (nonatomic, readonly) BOOL installationIdentificationType;
/** /**
* removes all previously stored authentication tokens, UDIDs, etc * removes all previously stored authentication tokens, UDIDs, etc
*/ */

View File

@ -297,6 +297,9 @@
/** /**
Reference to the initialized BITAuthenticator module Reference to the initialized BITAuthenticator module
The authenticator is disabled by default. To enable it you need to set
`[BITAuthenticator authenticationType]` and `[BITAuthenticator validationType]`
Returns the BITAuthenticator instance initialized by BITHockeyManager Returns the BITAuthenticator instance initialized by BITHockeyManager
@see configureWithIdentifier:delegate: @see configureWithIdentifier:delegate:
@ -305,6 +308,7 @@
*/ */
@property (nonatomic, strong, readonly) BITAuthenticator *authenticator; @property (nonatomic, strong, readonly) BITAuthenticator *authenticator;
///----------------------------------------------------------------------------- ///-----------------------------------------------------------------------------
/// @name Environment /// @name Environment
///----------------------------------------------------------------------------- ///-----------------------------------------------------------------------------

View File

@ -55,6 +55,8 @@
BOOL _validAppIdentifier; BOOL _validAppIdentifier;
BOOL _startManagerIsInvoked; BOOL _startManagerIsInvoked;
BOOL _startUpdateManagerIsInvoked;
} }
#pragma mark - Private Class Methods #pragma mark - Private Class Methods
@ -103,11 +105,13 @@
_disableCrashManager = NO; _disableCrashManager = NO;
_disableUpdateManager = NO; _disableUpdateManager = NO;
_enableStoreUpdateManager = NO;
_disableFeedbackManager = NO; _disableFeedbackManager = NO;
_enableStoreUpdateManager = NO;
_appStoreEnvironment = NO; _appStoreEnvironment = NO;
_startManagerIsInvoked = NO; _startManagerIsInvoked = NO;
_startUpdateManagerIsInvoked = NO;
#if !TARGET_IPHONE_SIMULATOR #if !TARGET_IPHONE_SIMULATOR
// check if we are really in an app store environment // check if we are really in an app store environment
@ -158,15 +162,6 @@
BITHockeyLog(@"INFO: Starting HockeyManager"); BITHockeyLog(@"INFO: Starting HockeyManager");
_startManagerIsInvoked = YES; _startManagerIsInvoked = YES;
// start Authenticator
if ( YES /* ![self isAuthenticatorDisabled] */) {
BITHockeyLog(@"INFO: Start Authenticator");
if (_serverURL) {
[_authenticator setServerURL:_serverURL];
}
[_authenticator startManager];
}
// start CrashManager // start CrashManager
if (![self isCrashManagerDisabled]) { if (![self isCrashManagerDisabled]) {
BITHockeyLog(@"INFO: Start CrashManager"); BITHockeyLog(@"INFO: Start CrashManager");
@ -176,19 +171,6 @@
[_crashManager startManager]; [_crashManager startManager];
} }
// Setup UpdateManager
if (![self isUpdateManagerDisabled]
#if JIRA_MOBILE_CONNECT_SUPPORT_ENABLED
|| [[self class] isJMCPresent]
#endif
) {
BITHockeyLog(@"INFO: Start UpdateManager with small delay");
if (_serverURL) {
[_updateManager setServerURL:_serverURL];
}
[_updateManager performSelector:@selector(startManager) withObject:nil afterDelay:0.5f];
}
// start StoreUpdateManager // start StoreUpdateManager
if ([self isStoreUpdateManagerEnabled]) { if ([self isStoreUpdateManagerEnabled]) {
BITHockeyLog(@"INFO: Start StoreUpdateManager"); BITHockeyLog(@"INFO: Start StoreUpdateManager");
@ -206,13 +188,29 @@
} }
[_feedbackManager performSelector:@selector(startManager) withObject:nil afterDelay:1.0f]; [_feedbackManager performSelector:@selector(startManager) withObject:nil afterDelay:1.0f];
} }
// start Authenticator
if (![self isAppStoreEnvironment]) {
// hook into manager with kvo!
[_authenticator addObserver:self forKeyPath:@"installationIdentificationValidated" options:0 context:nil];
[_authenticator addObserver:self forKeyPath:@"installationIdentifier" options:0 context:nil];
[_authenticator addObserver:self forKeyPath:@"installationIdentificationType" options:0 context:nil];
BITHockeyLog(@"INFO: Start Authenticator");
if (_serverURL) {
[_authenticator setServerURL:_serverURL];
}
[_authenticator startManager];
} }
// Setup UpdateManager
- (void)validateStartManagerIsInvoked { if (![self isUpdateManagerDisabled]
if (_validAppIdentifier && !_appStoreEnvironment) { #if JIRA_MOBILE_CONNECT_SUPPORT_ENABLED
if (!_startManagerIsInvoked) { || [[self class] isJMCPresent]
NSLog(@"[HockeySDK] ERROR: You did not call [[BITHockeyManager sharedHockeyManager] startManager] to startup the HockeySDK! Please do so after setting up all properties. The SDK is NOT running."); #endif
) {
if ([self.authenticator installationIdentificationValidated]) {
[self invokeStartUpdateManager];
} }
} }
} }
@ -227,9 +225,11 @@
- (void)setEnableStoreUpdateManager:(BOOL)enableStoreUpdateManager { - (void)setEnableStoreUpdateManager:(BOOL)enableStoreUpdateManager {
_enableStoreUpdateManager = enableStoreUpdateManager; if (_storeUpdateManager) {
[_storeUpdateManager setEnableStoreUpdateManager:enableStoreUpdateManager]; [_storeUpdateManager setEnableStoreUpdateManager:enableStoreUpdateManager];
} }
_enableStoreUpdateManager = enableStoreUpdateManager;
}
- (void)setDisableFeedbackManager:(BOOL)disableFeedbackManager { - (void)setDisableFeedbackManager:(BOOL)disableFeedbackManager {
@ -253,8 +253,71 @@
} }
#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
BOOL updateManagerIsAvailable = (![self isAppStoreEnvironment] && ![self isUpdateManagerDisabled]);
// only make changes if we are visible
if ([keyPath isEqualToString:@"installationIdentificationValidated"] &&
change[@"installationIdentificationValidated"] &&
[change[@"installationIdentificationValidated"] isKindOfClass:[NSNumber class]] ) {
if (updateManagerIsAvailable) {
BOOL isValidated = [(NSNumber *)change[@"installationIdentificationValidated"] boolValue];
[_updateManager setInstallationIdentificationValidated:isValidated];
if (isValidated) {
[self invokeStartUpdateManager];
}
}
} else if ([keyPath isEqualToString:@"installationIdentifier"] &&
change[@"installationIdentifier"]) {
if (updateManagerIsAvailable) {
[_updateManager setInstallationIdentifier:change[@"installationIdentifier"]];
}
} else if ([keyPath isEqualToString:@"installationIdentificationType"] &&
change[@"installationIdentificationType"]) {
if (updateManagerIsAvailable) {
[_updateManager setInstallationIdentificationType:change[@"installationIdentificationType"]];
}
#if JIRA_MOBILE_CONNECT_SUPPORT_ENABLED
} else if (([object trackerConfig]) && ([[object trackerConfig] isKindOfClass:[NSDictionary class]])) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *trackerConfig = [[defaults valueForKey:@"BITTrackerConfigurations"] mutableCopy];
if (!trackerConfig) {
trackerConfig = [NSMutableDictionary dictionaryWithCapacity:1];
}
[trackerConfig setValue:[object trackerConfig] forKey:_appIdentifier];
[defaults setValue:trackerConfig forKey:@"BITTrackerConfigurations"];
[defaults synchronize];
[self configureJMC];
#endif
}
}
#pragma mark - Private Instance Methods #pragma mark - Private Instance Methods
- (void)validateStartManagerIsInvoked {
if (_validAppIdentifier && !_appStoreEnvironment) {
if (!_startManagerIsInvoked) {
NSLog(@"[HockeySDK] ERROR: You did not call [[BITHockeyManager sharedHockeyManager] startManager] to startup the HockeySDK! Please do so after setting up all properties. The SDK is NOT running.");
}
}
}
- (void)invokeStartUpdateManager {
if (_startUpdateManagerIsInvoked) return;
_startUpdateManagerIsInvoked = YES;
BITHockeyLog(@"INFO: Start UpdateManager");
if (_serverURL) {
[_updateManager setServerURL:_serverURL];
}
[_updateManager performSelector:@selector(startManager) withObject:nil afterDelay:0.5f];
}
- (BOOL)isSetUpOnMainThread { - (BOOL)isSetUpOnMainThread {
NSString *errorString = @"ERROR: This SDK has to be setup on the main thread!"; NSString *errorString = @"ERROR: This SDK has to be setup on the main thread!";
@ -424,21 +487,6 @@
} }
} }
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (([object trackerConfig]) && ([[object trackerConfig] isKindOfClass:[NSDictionary class]])) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *trackerConfig = [[defaults valueForKey:@"BITTrackerConfigurations"] mutableCopy];
if (!trackerConfig) {
trackerConfig = [NSMutableDictionary dictionaryWithCapacity:1];
}
[trackerConfig setValue:[object trackerConfig] forKey:_appIdentifier];
[defaults setValue:trackerConfig forKey:@"BITTrackerConfigurations"];
[defaults synchronize];
[self configureJMC];
}
}
#endif #endif
@end @end

View File

@ -101,6 +101,7 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) {
NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter]; NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
[dnc addObserver:self selector:@selector(didBecomeActiveActions) name:UIApplicationDidBecomeActiveNotification object:nil]; [dnc addObserver:self selector:@selector(didBecomeActiveActions) name:UIApplicationDidBecomeActiveNotification object:nil];
[dnc addObserver:self selector:@selector(didBecomeActiveActions) name:BITHockeyNetworkDidBecomeReachableNotification object:nil]; [dnc addObserver:self selector:@selector(didBecomeActiveActions) name:BITHockeyNetworkDidBecomeReachableNotification object:nil];
_installationIdentifier = [self stringValueFromKeychainForKey:kBITUpdateInstallationIdentifier];
_didSetupDidBecomeActiveNotifications = YES; _didSetupDidBecomeActiveNotifications = YES;
} }
} }
@ -110,6 +111,7 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
} }
#pragma mark - Expiry #pragma mark - Expiry
- (BOOL)expiryDateReached { - (BOOL)expiryDateReached {
@ -166,8 +168,7 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) {
if (newVersion) { if (newVersion) {
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithDouble:[[NSDate date] timeIntervalSinceReferenceDate]] forKey:kBITUpdateDateOfVersionInstallation]; [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithDouble:[[NSDate date] timeIntervalSinceReferenceDate]] forKey:kBITUpdateDateOfVersionInstallation];
[[NSUserDefaults standardUserDefaults] setObject:_uuid forKey:kBITUpdateUsageTimeForUUID]; [[NSUserDefaults standardUserDefaults] setObject:_uuid forKey:kBITUpdateUsageTimeForUUID];
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithDouble:0] forKey:kBITUpdateUsageTimeOfCurrentVersion]; [self storeUsageTimeForCurrentVersion:[NSNumber numberWithDouble:0]];
[[NSUserDefaults standardUserDefaults] synchronize];
} }
} }
@ -177,7 +178,11 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) {
double timeDifference = [[NSDate date] timeIntervalSinceReferenceDate] - [_usageStartTimestamp timeIntervalSinceReferenceDate]; double timeDifference = [[NSDate date] timeIntervalSinceReferenceDate] - [_usageStartTimestamp timeIntervalSinceReferenceDate];
double previousTimeDifference = [(NSNumber *)[[NSUserDefaults standardUserDefaults] valueForKey:kBITUpdateUsageTimeOfCurrentVersion] doubleValue]; double previousTimeDifference = [(NSNumber *)[[NSUserDefaults standardUserDefaults] valueForKey:kBITUpdateUsageTimeOfCurrentVersion] doubleValue];
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithDouble:previousTimeDifference + timeDifference] forKey:kBITUpdateUsageTimeOfCurrentVersion]; [self storeUsageTimeForCurrentVersion:[NSNumber numberWithDouble:previousTimeDifference + timeDifference]];
}
- (void) storeUsageTimeForCurrentVersion:(NSNumber *)usageTime {
[[NSUserDefaults standardUserDefaults] setObject:usageTime forKey:kBITUpdateUsageTimeOfCurrentVersion];
[[NSUserDefaults standardUserDefaults] synchronize]; [[NSUserDefaults standardUserDefaults] synchronize];
} }
@ -534,6 +539,7 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) {
- (void)checkForUpdate { - (void)checkForUpdate {
if (![self isAppStoreEnvironment] && ![self isUpdateManagerDisabled]) { if (![self isAppStoreEnvironment] && ![self isUpdateManagerDisabled]) {
if ([self expiryDateReached]) return; if ([self expiryDateReached]) return;
if (![self installationIdentificationValidated]) return;
if (self.isUpdateAvailable && [self hasNewerMandatoryVersion]) { if (self.isUpdateAvailable && [self hasNewerMandatoryVersion]) {
[self showCheckForUpdateAlert]; [self showCheckForUpdateAlert];
@ -565,6 +571,14 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) {
BITHOCKEY_VERSION, BITHOCKEY_VERSION,
_uuid]; _uuid];
// add installationIdentificationType and installationIdentifier if available
if (self.installationIdentifier && self.installationIdentificationType) {
[parameter appendFormat:@"&%@=%@",
bit_URLEncodedString(self.installationIdentificationType),
bit_URLEncodedString(self.installationIdentifier)
];
}
// add additional statistics if user didn't disable flag // add additional statistics if user didn't disable flag
if (_sendUsageData) { if (_sendUsageData) {
[parameter appendFormat:@"&app_version=%@&os=iOS&os_version=%@&device=%@&lang=%@&first_start_at=%@&usage_time=%@", [parameter appendFormat:@"&app_version=%@&os=iOS&os_version=%@&device=%@&lang=%@&first_start_at=%@&usage_time=%@",
@ -863,6 +877,26 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) {
} }
} }
- (void)setInstallationIdentificationValidated:(BOOL)installationIdentificationValidated {
if (installationIdentificationValidated != _installationIdentificationValidated) {
}
}
- (void)setInstallationIdentifier:(NSString *)installationIdentifier {
if (![_installationIdentifier isEqualToString:installationIdentifier]) {
if (installationIdentifier) {
[self addStringValueToKeychain:installationIdentifier forKey:kBITUpdateInstallationIdentifier];
} else {
[self removeKeyFromKeychain:kBITUpdateInstallationIdentifier];
}
// we need to reset the usage time, because the user/device may have changed
[self storeUsageTimeForCurrentVersion:[NSNumber numberWithDouble:0]];
self.usageStartTimestamp = [NSDate date];
}
}
#pragma mark - UIAlertViewDelegate #pragma mark - UIAlertViewDelegate

View File

@ -58,6 +58,12 @@
@property (nonatomic, strong) NSString *companyName; @property (nonatomic, strong) NSString *companyName;
@property (nonatomic, strong) NSString *installationIdentifier;
@property (nonatomic, strong) NSString *installationIdentificationType;
@property (nonatomic) BOOL installationIdentificationValidated;
// if YES, the API will return an existing JMC config // if YES, the API will return an existing JMC config
// if NO, the API will return only version information // if NO, the API will return only version information
@property (nonatomic, assign) BOOL checkForTracker; @property (nonatomic, assign) BOOL checkForTracker;

View File

@ -49,8 +49,7 @@
#define kBITUpdateDateOfVersionInstallation @"BITUpdateDateOfVersionInstallation" #define kBITUpdateDateOfVersionInstallation @"BITUpdateDateOfVersionInstallation"
#define kBITUpdateUsageTimeOfCurrentVersion @"BITUpdateUsageTimeOfCurrentVersion" #define kBITUpdateUsageTimeOfCurrentVersion @"BITUpdateUsageTimeOfCurrentVersion"
#define kBITUpdateUsageTimeForUUID @"BITUpdateUsageTimeForUUID" #define kBITUpdateUsageTimeForUUID @"BITUpdateUsageTimeForUUID"
#define kBITUpdateAuthorizedVersion @"BITUpdateAuthorizedVersion" #define kBITUpdateInstallationIdentifier @"BITUpdateInstallationIdentifier"
#define kBITUpdateAuthorizedToken @"BITUpdateAuthorizedToken"
#define kBITStoreUpdateDateOfLastCheck @"BITStoreUpdateDateOfLastCheck" #define kBITStoreUpdateDateOfLastCheck @"BITStoreUpdateDateOfLastCheck"
#define kBITStoreUpdateLastStoreVersion @"BITStoreUpdateLastStoreVersion" #define kBITStoreUpdateLastStoreVersion @"BITStoreUpdateLastStoreVersion"