Ben Copsey

Added lock to mediate access to session credentials

Added a couple of comments
Add new test to ensure credentials are not reused on a different server
@@ -28,9 +28,14 @@ NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain"; @@ -28,9 +28,14 @@ NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain";
28 28
29 static const CFOptionFlags kNetworkEvents = kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | kCFStreamEventEndEncountered | kCFStreamEventErrorOccurred; 29 static const CFOptionFlags kNetworkEvents = kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | kCFStreamEventEndEncountered | kCFStreamEventErrorOccurred;
30 30
  31 +// In memory caches of credentials, used on when useSessionPersistance is YES
31 static NSMutableArray *sessionCredentialsStore = nil; 32 static NSMutableArray *sessionCredentialsStore = nil;
32 static NSMutableArray *sessionProxyCredentialsStore = nil; 33 static NSMutableArray *sessionProxyCredentialsStore = nil;
33 34
  35 +// This lock mediates access to session credentials
  36 +static NSRecursiveLock *sessionCredentialsLock = nil;
  37 +
  38 +// We keep track of cookies we have received here so we can remove them from the sharedHTTPCookieStorage later
34 static NSMutableArray *sessionCookies = nil; 39 static NSMutableArray *sessionCookies = nil;
35 40
36 // The number of times we will allow requests to redirect before we fail with a redirection error 41 // The number of times we will allow requests to redirect before we fail with a redirection error
@@ -2080,6 +2085,9 @@ static NSRecursiveLock *delegateAuthenticationLock = nil; @@ -2080,6 +2085,9 @@ static NSRecursiveLock *delegateAuthenticationLock = nil;
2080 if (!sessionProxyCredentialsStore) { 2085 if (!sessionProxyCredentialsStore) {
2081 sessionProxyCredentialsStore = [[NSMutableArray alloc] init]; 2086 sessionProxyCredentialsStore = [[NSMutableArray alloc] init];
2082 } 2087 }
  2088 + if (!sessionCredentialsLock) {
  2089 + sessionCredentialsLock = [[NSRecursiveLock alloc] init];
  2090 + }
2083 return sessionProxyCredentialsStore; 2091 return sessionProxyCredentialsStore;
2084 } 2092 }
2085 2093
@@ -2088,66 +2096,84 @@ static NSRecursiveLock *delegateAuthenticationLock = nil; @@ -2088,66 +2096,84 @@ static NSRecursiveLock *delegateAuthenticationLock = nil;
2088 if (!sessionCredentialsStore) { 2096 if (!sessionCredentialsStore) {
2089 sessionCredentialsStore = [[NSMutableArray alloc] init]; 2097 sessionCredentialsStore = [[NSMutableArray alloc] init];
2090 } 2098 }
  2099 + if (!sessionCredentialsLock) {
  2100 + sessionCredentialsLock = [[NSRecursiveLock alloc] init];
  2101 + }
2091 return sessionCredentialsStore; 2102 return sessionCredentialsStore;
2092 } 2103 }
2093 2104
2094 + (void)storeProxyAuthenticationCredentialsInSessionStore:(NSDictionary *)credentials 2105 + (void)storeProxyAuthenticationCredentialsInSessionStore:(NSDictionary *)credentials
2095 { 2106 {
  2107 + [sessionCredentialsLock lock];
2096 [self removeProxyAuthenticationCredentialsFromSessionStore:[credentials objectForKey:@"Credentials"]]; 2108 [self removeProxyAuthenticationCredentialsFromSessionStore:[credentials objectForKey:@"Credentials"]];
2097 [[[self class] sessionProxyCredentialsStore] addObject:credentials]; 2109 [[[self class] sessionProxyCredentialsStore] addObject:credentials];
  2110 + [sessionCredentialsLock unlock];
2098 } 2111 }
2099 2112
2100 + (void)storeAuthenticationCredentialsInSessionStore:(NSDictionary *)credentials 2113 + (void)storeAuthenticationCredentialsInSessionStore:(NSDictionary *)credentials
2101 { 2114 {
  2115 + [sessionCredentialsLock lock];
2102 [self removeAuthenticationCredentialsFromSessionStore:[credentials objectForKey:@"Credentials"]]; 2116 [self removeAuthenticationCredentialsFromSessionStore:[credentials objectForKey:@"Credentials"]];
2103 [[[self class] sessionCredentialsStore] addObject:credentials]; 2117 [[[self class] sessionCredentialsStore] addObject:credentials];
  2118 + [sessionCredentialsLock unlock];
2104 } 2119 }
2105 2120
2106 + (void)removeProxyAuthenticationCredentialsFromSessionStore:(NSDictionary *)credentials 2121 + (void)removeProxyAuthenticationCredentialsFromSessionStore:(NSDictionary *)credentials
2107 { 2122 {
  2123 + [sessionCredentialsLock lock];
2108 NSMutableArray *sessionCredentialsList = [[self class] sessionProxyCredentialsStore]; 2124 NSMutableArray *sessionCredentialsList = [[self class] sessionProxyCredentialsStore];
2109 int i; 2125 int i;
2110 for (i=0; i<[sessionCredentialsList count]; i++) { 2126 for (i=0; i<[sessionCredentialsList count]; i++) {
2111 NSDictionary *theCredentials = [sessionCredentialsList objectAtIndex:i]; 2127 NSDictionary *theCredentials = [sessionCredentialsList objectAtIndex:i];
2112 if ([theCredentials objectForKey:@"Credentials"] == credentials) { 2128 if ([theCredentials objectForKey:@"Credentials"] == credentials) {
2113 [sessionCredentialsList removeObjectAtIndex:i]; 2129 [sessionCredentialsList removeObjectAtIndex:i];
  2130 + [sessionCredentialsLock unlock];
2114 return; 2131 return;
2115 } 2132 }
2116 - } 2133 + }
  2134 + [sessionCredentialsLock unlock];
2117 } 2135 }
2118 2136
2119 + (void)removeAuthenticationCredentialsFromSessionStore:(NSDictionary *)credentials 2137 + (void)removeAuthenticationCredentialsFromSessionStore:(NSDictionary *)credentials
2120 { 2138 {
  2139 + [sessionCredentialsLock lock];
2121 NSMutableArray *sessionCredentialsList = [[self class] sessionCredentialsStore]; 2140 NSMutableArray *sessionCredentialsList = [[self class] sessionCredentialsStore];
2122 int i; 2141 int i;
2123 for (i=0; i<[sessionCredentialsList count]; i++) { 2142 for (i=0; i<[sessionCredentialsList count]; i++) {
2124 NSDictionary *theCredentials = [sessionCredentialsList objectAtIndex:i]; 2143 NSDictionary *theCredentials = [sessionCredentialsList objectAtIndex:i];
2125 if ([theCredentials objectForKey:@"Credentials"] == credentials) { 2144 if ([theCredentials objectForKey:@"Credentials"] == credentials) {
2126 [sessionCredentialsList removeObjectAtIndex:i]; 2145 [sessionCredentialsList removeObjectAtIndex:i];
  2146 + [sessionCredentialsLock unlock];
2127 return; 2147 return;
2128 } 2148 }
2129 - } 2149 + }
  2150 + [sessionCredentialsLock unlock];
2130 } 2151 }
2131 2152
2132 - (NSDictionary *)findSessionProxyAuthenticationCredentials 2153 - (NSDictionary *)findSessionProxyAuthenticationCredentials
2133 { 2154 {
  2155 + [sessionCredentialsLock lock];
2134 NSMutableArray *sessionCredentialsList = [[self class] sessionProxyCredentialsStore]; 2156 NSMutableArray *sessionCredentialsList = [[self class] sessionProxyCredentialsStore];
2135 for (NSDictionary *theCredentials in sessionCredentialsList) { 2157 for (NSDictionary *theCredentials in sessionCredentialsList) {
2136 if ([[theCredentials objectForKey:@"Host"] isEqualTo:[self proxyHost]] && [[theCredentials objectForKey:@"Port"] intValue] == [self proxyPort]) { 2158 if ([[theCredentials objectForKey:@"Host"] isEqualTo:[self proxyHost]] && [[theCredentials objectForKey:@"Port"] intValue] == [self proxyPort]) {
  2159 + [sessionCredentialsLock unlock];
2137 return theCredentials; 2160 return theCredentials;
2138 } 2161 }
2139 } 2162 }
  2163 + [sessionCredentialsLock unlock];
2140 return nil; 2164 return nil;
2141 } 2165 }
2142 2166
2143 2167
2144 - (NSDictionary *)findSessionAuthenticationCredentials 2168 - (NSDictionary *)findSessionAuthenticationCredentials
2145 { 2169 {
  2170 + [sessionCredentialsLock lock];
2146 NSMutableArray *sessionCredentialsList = [[self class] sessionCredentialsStore]; 2171 NSMutableArray *sessionCredentialsList = [[self class] sessionCredentialsStore];
2147 // Find an exact match 2172 // Find an exact match
2148 for (NSDictionary *theCredentials in sessionCredentialsList) { 2173 for (NSDictionary *theCredentials in sessionCredentialsList) {
2149 if ([[theCredentials objectForKey:@"URL"] isEqualTo:[self url]]) { 2174 if ([[theCredentials objectForKey:@"URL"] isEqualTo:[self url]]) {
2150 if (![self responseStatusCode] || [[theCredentials objectForKey:@"AuthenticationRealm"] isEqualTo:[self authenticationRealm]]) { 2175 if (![self responseStatusCode] || [[theCredentials objectForKey:@"AuthenticationRealm"] isEqualTo:[self authenticationRealm]]) {
  2176 + [sessionCredentialsLock unlock];
2151 return theCredentials; 2177 return theCredentials;
2152 } 2178 }
2153 } 2179 }
@@ -2158,10 +2184,12 @@ static NSRecursiveLock *delegateAuthenticationLock = nil; @@ -2158,10 +2184,12 @@ static NSRecursiveLock *delegateAuthenticationLock = nil;
2158 NSURL *theURL = [theCredentials objectForKey:@"URL"]; 2184 NSURL *theURL = [theCredentials objectForKey:@"URL"];
2159 if ([[theURL host] isEqualTo:[requestURL host]] && [[theURL port] isEqualTo:[requestURL port]] && [[theURL scheme] isEqualTo:[requestURL scheme]]) { 2185 if ([[theURL host] isEqualTo:[requestURL host]] && [[theURL port] isEqualTo:[requestURL port]] && [[theURL scheme] isEqualTo:[requestURL scheme]]) {
2160 if (![self responseStatusCode] || [[theCredentials objectForKey:@"AuthenticationRealm"] isEqualTo:[self authenticationRealm]]) { 2186 if (![self responseStatusCode] || [[theCredentials objectForKey:@"AuthenticationRealm"] isEqualTo:[self authenticationRealm]]) {
  2187 + [sessionCredentialsLock unlock];
2161 return theCredentials; 2188 return theCredentials;
2162 } 2189 }
2163 } 2190 }
2164 } 2191 }
  2192 + [sessionCredentialsLock unlock];
2165 return nil; 2193 return nil;
2166 } 2194 }
2167 2195
@@ -2250,7 +2278,7 @@ static NSRecursiveLock *delegateAuthenticationLock = nil; @@ -2250,7 +2278,7 @@ static NSRecursiveLock *delegateAuthenticationLock = nil;
2250 + (void)clearSession 2278 + (void)clearSession
2251 { 2279 {
2252 [[[self class] sessionCredentialsStore] removeAllObjects]; 2280 [[[self class] sessionCredentialsStore] removeAllObjects];
2253 - [ASIHTTPRequest setSessionCookies:nil]; 2281 + [[self class] setSessionCookies:nil];
2254 } 2282 }
2255 2283
2256 #pragma mark gzip decompression 2284 #pragma mark gzip decompression
@@ -456,8 +456,9 @@ @@ -456,8 +456,9 @@
456 456
457 - (void)testBasicAuthentication 457 - (void)testBasicAuthentication
458 { 458 {
  459 + [ASIHTTPRequest clearSession];
459 460
460 - NSURL *url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/basic-authentication"] autorelease]; 461 + NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/basic-authentication"];
461 ASIHTTPRequest *request; 462 ASIHTTPRequest *request;
462 BOOL success; 463 BOOL success;
463 NSError *err; 464 NSError *err;
@@ -514,6 +515,17 @@ @@ -514,6 +515,17 @@
514 [request start]; 515 [request start];
515 err = [request error]; 516 err = [request error];
516 GHAssertNil(err,@"Failed to use stored credentials"); 517 GHAssertNil(err,@"Failed to use stored credentials");
  518 +
  519 + // Ok, now let's test on a different server
  520 + url = [NSURL URLWithString:@"https://selfsigned.allseeing-i.com/ASIHTTPRequest/tests/basic-authentication"];
  521 + request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
  522 + [request setUseSessionPersistance:YES];
  523 + [request setUseKeychainPersistance:NO];
  524 + [request setValidatesSecureCertificate:NO];
  525 + [request start];
  526 + success = [[request error] code] == ASIAuthenticationErrorType;
  527 + GHAssertTrue(success,@"Reused credentials when we shouldn't have");
  528 +
517 } 529 }
518 530
519 531