| #import "HTTPAuthenticationRequest.h" |
| #import "HTTPMessage.h" |
| |
| #if ! __has_feature(objc_arc) |
| #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). |
| #endif |
| |
| @interface HTTPAuthenticationRequest (PrivateAPI) |
| - (NSString *)quotedSubHeaderFieldValue:(NSString *)param fromHeaderFieldValue:(NSString *)header; |
| - (NSString *)nonquotedSubHeaderFieldValue:(NSString *)param fromHeaderFieldValue:(NSString *)header; |
| @end |
| |
| |
| @implementation HTTPAuthenticationRequest |
| |
| - (id)initWithRequest:(HTTPMessage *)request |
| { |
| if ((self = [super init])) |
| { |
| NSString *authInfo = [request headerField:@"Authorization"]; |
| |
| isBasic = NO; |
| if ([authInfo length] >= 6) |
| { |
| isBasic = [[authInfo substringToIndex:6] caseInsensitiveCompare:@"Basic "] == NSOrderedSame; |
| } |
| |
| isDigest = NO; |
| if ([authInfo length] >= 7) |
| { |
| isDigest = [[authInfo substringToIndex:7] caseInsensitiveCompare:@"Digest "] == NSOrderedSame; |
| } |
| |
| if (isBasic) |
| { |
| NSMutableString *temp = [[authInfo substringFromIndex:6] mutableCopy]; |
| CFStringTrimWhitespace((__bridge CFMutableStringRef)temp); |
| |
| base64Credentials = [temp copy]; |
| } |
| |
| if (isDigest) |
| { |
| username = [self quotedSubHeaderFieldValue:@"username" fromHeaderFieldValue:authInfo]; |
| realm = [self quotedSubHeaderFieldValue:@"realm" fromHeaderFieldValue:authInfo]; |
| nonce = [self quotedSubHeaderFieldValue:@"nonce" fromHeaderFieldValue:authInfo]; |
| uri = [self quotedSubHeaderFieldValue:@"uri" fromHeaderFieldValue:authInfo]; |
| |
| // It appears from RFC 2617 that the qop is to be given unquoted |
| // Tests show that Firefox performs this way, but Safari does not |
| // Thus we'll attempt to retrieve the value as nonquoted, but we'll verify it doesn't start with a quote |
| qop = [self nonquotedSubHeaderFieldValue:@"qop" fromHeaderFieldValue:authInfo]; |
| if(qop && ([qop characterAtIndex:0] == '"')) |
| { |
| qop = [self quotedSubHeaderFieldValue:@"qop" fromHeaderFieldValue:authInfo]; |
| } |
| |
| nc = [self nonquotedSubHeaderFieldValue:@"nc" fromHeaderFieldValue:authInfo]; |
| cnonce = [self quotedSubHeaderFieldValue:@"cnonce" fromHeaderFieldValue:authInfo]; |
| response = [self quotedSubHeaderFieldValue:@"response" fromHeaderFieldValue:authInfo]; |
| } |
| } |
| return self; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| #pragma mark Accessors: |
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| - (BOOL)isBasic { |
| return isBasic; |
| } |
| |
| - (BOOL)isDigest { |
| return isDigest; |
| } |
| |
| - (NSString *)base64Credentials { |
| return base64Credentials; |
| } |
| |
| - (NSString *)username { |
| return username; |
| } |
| |
| - (NSString *)realm { |
| return realm; |
| } |
| |
| - (NSString *)nonce { |
| return nonce; |
| } |
| |
| - (NSString *)uri { |
| return uri; |
| } |
| |
| - (NSString *)qop { |
| return qop; |
| } |
| |
| - (NSString *)nc { |
| return nc; |
| } |
| |
| - (NSString *)cnonce { |
| return cnonce; |
| } |
| |
| - (NSString *)response { |
| return response; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| #pragma mark Private API: |
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| /** |
| * Retrieves a "Sub Header Field Value" from a given header field value. |
| * The sub header field is expected to be quoted. |
| * |
| * In the following header field: |
| * Authorization: Digest username="Mufasa", qop=auth, response="6629fae4939" |
| * The sub header field titled 'username' is quoted, and this method would return the value @"Mufasa". |
| **/ |
| - (NSString *)quotedSubHeaderFieldValue:(NSString *)param fromHeaderFieldValue:(NSString *)header |
| { |
| NSRange startRange = [header rangeOfString:[NSString stringWithFormat:@"%@=\"", param]]; |
| if(startRange.location == NSNotFound) |
| { |
| // The param was not found anywhere in the header |
| return nil; |
| } |
| |
| NSUInteger postStartRangeLocation = startRange.location + startRange.length; |
| NSUInteger postStartRangeLength = [header length] - postStartRangeLocation; |
| NSRange postStartRange = NSMakeRange(postStartRangeLocation, postStartRangeLength); |
| |
| NSRange endRange = [header rangeOfString:@"\"" options:0 range:postStartRange]; |
| if(endRange.location == NSNotFound) |
| { |
| // The ending double-quote was not found anywhere in the header |
| return nil; |
| } |
| |
| NSRange subHeaderRange = NSMakeRange(postStartRangeLocation, endRange.location - postStartRangeLocation); |
| return [header substringWithRange:subHeaderRange]; |
| } |
| |
| /** |
| * Retrieves a "Sub Header Field Value" from a given header field value. |
| * The sub header field is expected to not be quoted. |
| * |
| * In the following header field: |
| * Authorization: Digest username="Mufasa", qop=auth, response="6629fae4939" |
| * The sub header field titled 'qop' is nonquoted, and this method would return the value @"auth". |
| **/ |
| - (NSString *)nonquotedSubHeaderFieldValue:(NSString *)param fromHeaderFieldValue:(NSString *)header |
| { |
| NSRange startRange = [header rangeOfString:[NSString stringWithFormat:@"%@=", param]]; |
| if(startRange.location == NSNotFound) |
| { |
| // The param was not found anywhere in the header |
| return nil; |
| } |
| |
| NSUInteger postStartRangeLocation = startRange.location + startRange.length; |
| NSUInteger postStartRangeLength = [header length] - postStartRangeLocation; |
| NSRange postStartRange = NSMakeRange(postStartRangeLocation, postStartRangeLength); |
| |
| NSRange endRange = [header rangeOfString:@"," options:0 range:postStartRange]; |
| if(endRange.location == NSNotFound) |
| { |
| // The ending comma was not found anywhere in the header |
| // However, if the nonquoted param is at the end of the string, there would be no comma |
| // This is only possible if there are no spaces anywhere |
| NSRange endRange2 = [header rangeOfString:@" " options:0 range:postStartRange]; |
| if(endRange2.location != NSNotFound) |
| { |
| return nil; |
| } |
| else |
| { |
| return [header substringWithRange:postStartRange]; |
| } |
| } |
| else |
| { |
| NSRange subHeaderRange = NSMakeRange(postStartRangeLocation, endRange.location - postStartRangeLocation); |
| return [header substringWithRange:subHeaderRange]; |
| } |
| } |
| |
| @end |