berchan z
berchan z

Reputation: 11

Pop the Proxy Authentication dialog when a proxy challenge provides a 407 response with a Proxy-Authenticate header

In my App I've configured a proxy for the NSURLSessionConfiguration object so the App can use the proxy. When the proxy requires authentication, the App will ask for username and password via the delegate method "URLSession:task:didReceiveChallenge:completionHandler:" and makes sure that the request can continue.

Normal in HTTP requests, but the HTTPS requests popup a dialog stating the proxy authentication is required and gives the user the choice to do this "later" or directly go to the system settings.

In addition, the dialog pops up even before the delegate method "didReceiveChallenge" of the NSUrlSession above, the application does not get an opportunity to provide credentials before iOS displays it.

Does anyone else seeing this and knows how to fix this?

proxy server response header:

HTTP/1.1 407 Proxy Authentication Required

Content-Type: text/html

X-Squid-Error: ERR_CACHE_ACCESS_DENIED 0

Proxy-Authenticate: Basic realm="Basic"

Proxy-Authenticate: Digest realm="Digest", nonce="xxxxxxxxxxxxxxxxxxxxxxxxxxx", qop="auth", stale=false

X-Cache: MISS from proxy.xxxx.com

Via: 1.1 proxy.xxxx.com

my demo code:

    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
config.connectionProxyDictionary = @{
                                     @"HTTPEnable" : @(1),
                                     (NSString *)kCFStreamPropertyHTTPProxyHost  : @"proxy.xxxx.com",
                                     (NSString *)kCFStreamPropertyHTTPProxyPort  : @(1234),
                                     @"HTTPSEnable": @(1),
                                     (NSString *)kCFStreamPropertyHTTPSProxyHost :@"proxy.xxxx.com",
                                     (NSString *)kCFStreamPropertyHTTPSProxyPort : @(4321)
                                    };

self.session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://www.xxxxx.com"] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60.0];
NSURLSessionTask  *task =  [self.session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    NSLog(@"result:%@  error: %@",data, error.description);
}];
[task resume];

#pragma mark - NSURLSessionTaskDelegate

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)taskdidReceiveChallenge:(NSURLAuthenticationChallenge *)challengecompletionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler{
NSLog(@"task:%@",challenge.protectionSpace.authenticationMethod);
if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPDigest) {
    NSURLCredential *cren = [NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistenceNone];
    if (completionHandler) {
        completionHandler(NSURLSessionAuthChallengeUseCredential,cren);
    }
}

}

Upvotes: 1

Views: 1843

Answers (1)

karajan
karajan

Reputation: 36

I found the solution here.It seems like such problems are bugs.Instead of using the URLSession:task:didReceiveChallenge:completionHandler: delegate, a good workaround is to add a "Proxy-Authorization" header to the NSURLSessionConfiguration.Here is the code based on here:

// 1 - define credentials as a string with format:
//    "username:password"
//
NSString *username = @"USERID";
NSString *password = @"SECRET";
NSString *authString = [NSString stringWithFormat:@"%@:%@",
                        username,
                        password];

// 2 - convert authString to an NSData instance
NSData *authData = [authString dataUsingEncoding:NSUTF8StringEncoding];

// 3 - build the header string with base64 encoded data
NSString *authHeader = [NSString stringWithFormat: @"Basic %@",
                        [authData base64EncodedStringWithOptions:0]];

// 4 - create an NSURLSessionConfiguration instance
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];

// 5 - add custom headers, including the Authorization header
[configuration setHTTPAdditionalHeaders:@{
                                          @"Proxy-Authorization": authHeader
                                          }
 ];

// 6 - set proxy dictionary
NSDictionary *proxyDict = @{
                            @"HTTPEnable"  : @1,
                            (NSString *)kCFStreamPropertyHTTPProxyHost  : @"ip",
                            (NSString *)kCFStreamPropertyHTTPProxyPort  : proxyPortNumber,

                            @"HTTPSEnable" : @1,
                            (NSString *)kCFStreamPropertyHTTPSProxyHost : @"ip",
                            (NSString *)kCFStreamPropertyHTTPSProxyPort : proxyPortNumber,

                            };
configuration.connectionProxyDictionary = proxyDict;

// 7 - create an NSURLSession instance
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:nil delegateQueue:operationQueue];

Upvotes: 2

Related Questions