redo authentication response parsing

* first check for HTTP Status codes
* then do parsing if it was a 200
* fix typo in error messages
* be more specific about the response
This commit is contained in:
Stephan Diederich 2013-09-12 22:16:44 +02:00
parent c534e5d566
commit 681c67a9dd
3 changed files with 98 additions and 91 deletions

View File

@ -130,9 +130,9 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
__weak typeof (self) weakSelf = self; __weak typeof (self) weakSelf = self;
[self.hockeyAppClient getPath:validationPath [self.hockeyAppClient getPath:validationPath
parameters:[self validationParameters] parameters:[self validationParameters]
completion:^(BITHTTPOperation *operation, id response, NSError *error) { completion:^(BITHTTPOperation *operation, NSData* responseData, NSError *error) {
typeof (self) strongSelf = weakSelf; typeof (self) strongSelf = weakSelf;
if(nil == response) { if(nil == responseData) {
NSDictionary *userInfo = nil; NSDictionary *userInfo = nil;
if(error) { if(error) {
userInfo = @{NSUnderlyingErrorKey : error}; userInfo = @{NSUnderlyingErrorKey : error};
@ -143,7 +143,7 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
[strongSelf validationFailedWithError:error completion:completion]; [strongSelf validationFailedWithError:error completion:completion];
} else { } else {
NSError *validationParseError = nil; NSError *validationParseError = nil;
BOOL isValidated = [strongSelf.class isValidationResponseValid:response error:&validationParseError]; BOOL isValidated = [strongSelf.class isValidationResponseValid:responseData error:&validationParseError];
if(isValidated) { if(isValidated) {
[strongSelf validationSucceededWithCompletion:completion]; [strongSelf validationSucceededWithCompletion:completion];
} else { } else {
@ -170,16 +170,16 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
if(nil == jsonObject) { if(nil == jsonObject) {
if(error) { if(error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain *error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorAPIServerReturnedInvalidRespone code:BITAuthenticatorAPIServerReturnedInvalidResponse
userInfo:(jsonParseError ? @{NSUnderlyingErrorKey : jsonParseError} : nil)]; userInfo:@{NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"Failed to authenticate. Please try again later.")}];
} }
return NO; return NO;
} }
if(![jsonObject isKindOfClass:[NSDictionary class]]) { if(![jsonObject isKindOfClass:[NSDictionary class]]) {
if(error) { if(error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain *error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorAPIServerReturnedInvalidRespone code:BITAuthenticatorAPIServerReturnedInvalidResponse
userInfo:nil]; userInfo:@{NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"Failed to authenticate. Please try again later.")}];
} }
return NO; return NO;
} }
@ -189,14 +189,14 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
if(error) { if(error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain *error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorNotAuthorized code:BITAuthenticatorNotAuthorized
userInfo:nil]; userInfo:@{NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"You are not authorized to use this app. Please check that you are a member of this app.")}];
} }
return NO; return NO;
} else if([status isEqualToString:@"not found"]) { } else if([status isEqualToString:@"not found"]) {
if(error) { if(error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain *error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorNotAuthorized code:BITAuthenticatorUnknownApplicationID
userInfo:nil]; userInfo:@{NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"Authorization error. Please contact the developer of the app.")}];
} }
return NO; return NO;
} else if([status isEqualToString:@"validated"]) { } else if([status isEqualToString:@"validated"]) {
@ -204,8 +204,8 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
} else { } else {
if(error) { if(error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain *error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorAPIServerReturnedInvalidRespone code:BITAuthenticatorAPIServerReturnedInvalidResponse
userInfo:nil]; userInfo:@{NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"Failed to authenticate. Please try again later.")}];
} }
return NO; return NO;
} }
@ -315,51 +315,18 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
NSURLRequest* request = [self requestForAuthenticationEmail:email password:password]; NSURLRequest* request = [self requestForAuthenticationEmail:email password:password];
__weak typeof (self) weakSelf = self; __weak typeof (self) weakSelf = self;
BITHTTPOperation *operation = [self.hockeyAppClient operationWithURLRequest:request BITHTTPOperation *operation = [self.hockeyAppClient operationWithURLRequest:request
completion:^(BITHTTPOperation *operation, id response, NSError *error) { completion:^(BITHTTPOperation *operation, NSData* responseData, NSError *error) {
typeof (self) strongSelf = weakSelf; typeof (self) strongSelf = weakSelf;
if(nil == response) { NSError *authParseError = nil;
NSError *error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain NSString *authToken = [strongSelf.class authenticationTokenFromURLResponse:operation.response
code:BITAuthenticatorAPIServerReturnedInvalidRespone data:responseData
userInfo:@{ error:&authParseError];
NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"Failed to authenticate. Please try again later.") if(nil == authToken) {
}]; completion(NO, authParseError);
completion(NO, error); } else {
} else if(401 == operation.response.statusCode) { //no need to call completion, we're dismissing it anyways
NSError *error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain [self didAuthenticateWithToken:authToken];
code:BITAuthenticatorNotAuthorized }}];
userInfo:@{
NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"Not authorized")
}];
completion(NO, error);
} else {
NSError *authParseError = nil;
NSString *authToken = [strongSelf.class authenticationTokenFromReponse:response
error:&authParseError];
NSError *error = nil;
if(nil == authToken) {
if([authParseError.domain isEqualToString:kBITAuthenticatorErrorDomain] &&
authParseError.code == BITAuthenticatorNotAuthorized) {
error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorNotAuthorized
userInfo:@{
NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"Not authorized"),
NSUnderlyingErrorKey : authParseError
}];
} else {
error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorErrorUnknown
userInfo:@{
NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"Failed to authenticate. Please try again later."),
NSUnderlyingErrorKey : authParseError
}];
}
completion(NO, error);
} else {
//no need to call completion, we're dismissing it anyways
[self didAuthenticateWithToken:authToken];
}
}
}];
[self.hockeyAppClient enqeueHTTPOperation:operation]; [self.hockeyAppClient enqeueHTTPOperation:operation];
} }
@ -398,51 +365,90 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
} }
+ (NSString *) authenticationTokenFromReponse:(id) response error:(NSError **) error { + (NSString *) authenticationTokenFromURLResponse:(NSHTTPURLResponse*) urlResponse data:(NSData*) data error:(NSError **) error {
NSParameterAssert(response); NSParameterAssert(urlResponse);
if(nil == urlResponse) {
if(error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorAPIServerReturnedInvalidResponse
userInfo:@{ NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"Failed to authenticate. Please try again later.")}];
}
return nil;
}
switch (urlResponse.statusCode) {
case 404:
if(error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorUnknownApplicationID
userInfo:@{
NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"Authorization error. Please contact the developer of the app.")
}];
}
break;
case 401:
if(error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorNotAuthorized
userInfo:@{
NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"Wrong email or password. Please check your credentials and try again.")
}];
}
break;
case 200:
//Do nothing, handled below
break;
default:
if(error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorAPIServerReturnedInvalidResponse
userInfo:@{ NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"Failed to authenticate. Please try again later.")}];
}
return nil;
break;
}
if(200 != urlResponse.statusCode) {
//make sure we have an error created if user wanted to have one
NSParameterAssert(0 == error || *error);
return nil;
}
NSAssert(urlResponse.statusCode == 200, @"Should be 200 now. Everything else should've been handled above");
NSError *jsonParseError = nil; NSError *jsonParseError = nil;
id jsonObject = [NSJSONSerialization JSONObjectWithData:response id jsonObject = [NSJSONSerialization JSONObjectWithData:data
options:0 options:0
error:&jsonParseError]; error:&jsonParseError];
if(nil == jsonObject) { //no json or unexpected json
if(nil == jsonObject || ![jsonObject isKindOfClass:[NSDictionary class]]) {
if(error) { if(error) {
NSDictionary *userInfo = @{NSLocalizedDescriptionKey: BITHockeyLocalizedString(@"Failed to authenticate. Please try again later.")};
if(jsonParseError) {
NSMutableDictionary *userInfoMutable = [userInfo mutableCopy];
userInfoMutable[NSUnderlyingErrorKey] = jsonParseError;
userInfo = userInfoMutable;
}
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain *error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorAPIServerReturnedInvalidRespone code:BITAuthenticatorAPIServerReturnedInvalidResponse
userInfo:(jsonParseError ? @{NSUnderlyingErrorKey : jsonParseError} : nil)]; userInfo:userInfo];
} }
return nil; return nil;
} }
if(![jsonObject isKindOfClass:[NSDictionary class]]) {
if(error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorAPIServerReturnedInvalidRespone
userInfo:nil];
}
return nil;
}
NSString *status = jsonObject[@"status"];
if(nil == status) {
if(error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorAPIServerReturnedInvalidRespone
userInfo:nil];
}
return nil;
} else if([status isEqualToString:@"identified"]) {
return jsonObject[@"iuid"];
} else if([status isEqualToString:@"authorized"]) {
return jsonObject[@"auid"];
} else {
if(error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorNotAuthorized
userInfo:nil];
}
return nil;
}
}
NSString *status = jsonObject[@"status"];
NSString *authToken = nil;
if([status isEqualToString:@"identified"]) {
authToken = jsonObject[@"iuid"];
} else if([status isEqualToString:@"authorized"]) {
authToken = jsonObject[@"auid"];
}
if(nil == authToken && error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorAPIServerReturnedInvalidResponse
userInfo:@{NSLocalizedDescriptionKey: BITHockeyLocalizedString(@"Failed to authenticate. Please try again later.")}];
}
return authToken;
}
- (void)authenticationViewControllerDidTapWebButton:(UIViewController *)viewController { - (void)authenticationViewControllerDidTapWebButton:(UIViewController *)viewController {
NSURL *hockeyWebbasedLoginURL = [self.webpageURL URLByAppendingPathComponent:[NSString stringWithFormat:@"apps/%@/authorize", self.encodedAppIdentifier]]; NSURL *hockeyWebbasedLoginURL = [self.webpageURL URLByAppendingPathComponent:[NSString stringWithFormat:@"apps/%@/authorize", self.encodedAppIdentifier]];

View File

@ -29,7 +29,7 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@class BITHTTPOperation; @class BITHTTPOperation;
typedef void (^BITNetworkCompletionBlock)(BITHTTPOperation* operation, id response, NSError* error); typedef void (^BITNetworkCompletionBlock)(BITHTTPOperation* operation, NSData* data, NSError* error);
@interface BITHTTPOperation : NSOperation @interface BITHTTPOperation : NSOperation

View File

@ -91,8 +91,9 @@ extern NSString *const __attribute__((unused)) kBITFeedbackErrorDomain;
typedef NS_ENUM(NSInteger, BITAuthenticatorReason) { typedef NS_ENUM(NSInteger, BITAuthenticatorReason) {
BITAuthenticatorErrorUnknown, BITAuthenticatorErrorUnknown,
BITAuthenticatorNetworkError, BITAuthenticatorNetworkError,
BITAuthenticatorAPIServerReturnedInvalidRespone, BITAuthenticatorAPIServerReturnedInvalidResponse,
BITAuthenticatorNotAuthorized, BITAuthenticatorNotAuthorized,
BITAuthenticatorUnknownApplicationID,
BITAuthenticatorAuthenticationCancelled, BITAuthenticatorAuthenticationCancelled,
BITAuthenticatorAuthorizationSecretMissing, BITAuthenticatorAuthorizationSecretMissing,
}; };