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;
/**
* Authenticator module used to identify and optionally authenticate the current
* app installation
* Authenticator module used to identify and optionally authenticate the current 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:
* 1) authenticate
* some kind of token is aquired depending on the authenticationType
* 2) verification
* the aquired token from step 1 is verified depending the validationType
* 2) validation
* the aquired token from step 1 is validated depending the validationType
*
* There are currently 3 ways of authentication:
* 1) authenticate the user via email only
* 2) authenticate the user via email & passwort (needs to have a HockeyApp Account)
* 3) authenticate the device via its UDID
* 1) authenticate the user via email only (`BITAuthenticatorAuthTypeEmail`)
* 2) authenticate the user via email & passwort (needs to have a HockeyApp Account) (`BITAuthenticatorAuthTypeEmailAndPassword`)
* 3) authenticate the device via its UDID (_Default_) (`BITAuthenticatorAuthTypeUDIDProvider`)
*
* Additionally, verification can be required:
* 1) never
* 2) optional
* 3) on first launch of every app version, never again until the next version is installed
* 4) every time the app becomes active (needs data connection)
* 1) never (`BITAuthenticatorValidationTypeNever`)
* 2) optional (`BITAuthenticatorValidationTypeOptional`)
* 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) (`BITAuthenticatorValidationTypeOnAppActive`)
*
*/
@interface BITAuthenticator : BITHockeyBaseManager
#pragma mark - Configuration
/**
* Defines the authentication mechanism to be used
*
* _Default_: BITAuthenticatorAuthTypeUDIDProvider
*/
@property (nonatomic, assign) BITAuthenticatorAuthType authenticationType;
/**
* defaults to BITAuthenticatorValidationTypeNever
* _Default_: BITAuthenticatorValidationTypeNever
*/
@property (nonatomic, assign) BITAuthenticatorValidationType validationType;

View File

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

View File

@ -60,6 +60,13 @@
@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
*/

View File

@ -297,6 +297,9 @@
/**
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
@see configureWithIdentifier:delegate:
@ -305,6 +308,7 @@
*/
@property (nonatomic, strong, readonly) BITAuthenticator *authenticator;
///-----------------------------------------------------------------------------
/// @name Environment
///-----------------------------------------------------------------------------

View File

@ -55,6 +55,8 @@
BOOL _validAppIdentifier;
BOOL _startManagerIsInvoked;
BOOL _startUpdateManagerIsInvoked;
}
#pragma mark - Private Class Methods
@ -103,11 +105,13 @@
_disableCrashManager = NO;
_disableUpdateManager = NO;
_enableStoreUpdateManager = NO;
_disableFeedbackManager = NO;
_enableStoreUpdateManager = NO;
_appStoreEnvironment = NO;
_startManagerIsInvoked = NO;
_startUpdateManagerIsInvoked = NO;
#if !TARGET_IPHONE_SIMULATOR
// check if we are really in an app store environment
@ -158,15 +162,6 @@
BITHockeyLog(@"INFO: Starting HockeyManager");
_startManagerIsInvoked = YES;
// start Authenticator
if ( YES /* ![self isAuthenticatorDisabled] */) {
BITHockeyLog(@"INFO: Start Authenticator");
if (_serverURL) {
[_authenticator setServerURL:_serverURL];
}
[_authenticator startManager];
}
// start CrashManager
if (![self isCrashManagerDisabled]) {
BITHockeyLog(@"INFO: Start CrashManager");
@ -176,19 +171,6 @@
[_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
if ([self isStoreUpdateManagerEnabled]) {
BITHockeyLog(@"INFO: Start StoreUpdateManager");
@ -206,13 +188,29 @@
}
[_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];
}
- (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.");
// Setup UpdateManager
if (![self isUpdateManagerDisabled]
#if JIRA_MOBILE_CONNECT_SUPPORT_ENABLED
|| [[self class] isJMCPresent]
#endif
) {
if ([self.authenticator installationIdentificationValidated]) {
[self invokeStartUpdateManager];
}
}
}
@ -227,9 +225,11 @@
- (void)setEnableStoreUpdateManager:(BOOL)enableStoreUpdateManager {
_enableStoreUpdateManager = enableStoreUpdateManager;
if (_storeUpdateManager) {
[_storeUpdateManager setEnableStoreUpdateManager:enableStoreUpdateManager];
}
_enableStoreUpdateManager = enableStoreUpdateManager;
}
- (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
- (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 {
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
@end

View File

@ -101,6 +101,7 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) {
NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
[dnc addObserver:self selector:@selector(didBecomeActiveActions) name:UIApplicationDidBecomeActiveNotification object:nil];
[dnc addObserver:self selector:@selector(didBecomeActiveActions) name:BITHockeyNetworkDidBecomeReachableNotification object:nil];
_installationIdentifier = [self stringValueFromKeychainForKey:kBITUpdateInstallationIdentifier];
_didSetupDidBecomeActiveNotifications = YES;
}
}
@ -110,6 +111,7 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
}
#pragma mark - Expiry
- (BOOL)expiryDateReached {
@ -166,8 +168,7 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) {
if (newVersion) {
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithDouble:[[NSDate date] timeIntervalSinceReferenceDate]] forKey:kBITUpdateDateOfVersionInstallation];
[[NSUserDefaults standardUserDefaults] setObject:_uuid forKey:kBITUpdateUsageTimeForUUID];
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithDouble:0] forKey:kBITUpdateUsageTimeOfCurrentVersion];
[[NSUserDefaults standardUserDefaults] synchronize];
[self storeUsageTimeForCurrentVersion:[NSNumber numberWithDouble:0]];
}
}
@ -177,7 +178,11 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) {
double timeDifference = [[NSDate date] timeIntervalSinceReferenceDate] - [_usageStartTimestamp timeIntervalSinceReferenceDate];
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];
}
@ -534,6 +539,7 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) {
- (void)checkForUpdate {
if (![self isAppStoreEnvironment] && ![self isUpdateManagerDisabled]) {
if ([self expiryDateReached]) return;
if (![self installationIdentificationValidated]) return;
if (self.isUpdateAvailable && [self hasNewerMandatoryVersion]) {
[self showCheckForUpdateAlert];
@ -565,6 +571,14 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) {
BITHOCKEY_VERSION,
_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
if (_sendUsageData) {
[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

View File

@ -58,6 +58,12 @@
@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 NO, the API will return only version information
@property (nonatomic, assign) BOOL checkForTracker;

View File

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