123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- #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
|