Search code examples
objective-ciosuiwebviewssl-certificatehttp-authentication

Need to view website with a self-signed certificate and http authentication


I am having trouble viewing a website that has a self-signed certificate and also requires HTTP authentication. Currently I am trying to implement it by using How to display the Authentication Challenge in UIWebView? and UIWebView to view self signed websites (No private api, not NSURLConnection) - is it possible? as guides on how to accomplish this. I'm also trying to use the private api method of bypassing self-signed certificates but I'm having trouble finding the link to it. But the private api header is:

@interface NSURLRequest (DummyInterface)
+ (BOOL)allowsAnyHTTPSCertificateForHost:(NSString*)host;
+ (void)setAllowsAnyHTTPSCertificate:(BOOL)allow forHost:(NSString*)host;
@end 

Then I have these as the important functions:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
{
    NSLog(@"Did start loading: %@ auth:%d", [[request URL] absoluteString], _authenticated);

      [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[URL host]];

   _request=[NSURLRequest requestWithURL:URL];

    if (!_authenticated) {
        _authenticated = NO;

        [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[URL host]];

        _urlConnection = [[NSURLConnection alloc] initWithRequest:_request delegate:self];

        [_urlConnection start];

       [mainWebView loadRequest:_request];

        return NO;
    }

    return YES;

}

Basically calls a nsurl connection to pass in log in credentials.

    #pragma mark - NURLConnection delegate

    - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
    {




        NSLog(@"WebController Got auth challange via NSURLConnection");

        [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[URL host]];

        if ([challenge previousFailureCount] == 0)
        {
            _authenticated = YES;



            NSURLCredential *credential = [NSURLCredential credentialWithUser:@"username"
              password:@"password"
                                                                   persistence:NSURLCredentialPersistenceForSession];

           [challenge.sender useCredential:credential forAuthenticationChallenge:challenge];

        NSLog(@"credential created");

    } else
    {
        NSLog(@"previous authentication failure");
        [[challenge sender] cancelAuthenticationChallenge:challenge];
    }
}

and

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
{
    NSLog(@"WebController received response via NSURLConnection");

    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
     NSLog(@"remote url returned error %d %@",[httpResponse statusCode],[NSHTTPURLResponse localizedStringForStatusCode:[httpResponse statusCode]]);

    NSLog(@"The response is =%@",response);


   _authenticated = YES;

  [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[URL host]];

    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:URL];

    [mainWebView loadRequest:urlRequest];

    [_urlConnection cancel];    
}

Solution

  • This is easy to implement using AFNetworking
    I did it by subclassing AFHTTPRequestOperation and adding this code to the init

    // SSL Support
    [self setAuthenticationChallengeBlock:^(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge) {
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
        }
    }];
    [self setAuthenticationAgainstProtectionSpaceBlock:^BOOL(NSURLConnection *connection, NSURLProtectionSpace *protectionSpace) {
        if([[protectionSpace authenticationMethod] isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            if(shouldAllowSelfSignedCert) {
                return YES; // Self-signed cert will be accepted
            } else {
                return NO;  // Self-signed cert will be rejected
            }
            // Note: it doesn't seem to matter what you return for a proper SSL cert
            //       only self-signed certs
        }
        // If no other authentication is required, return NO for everything else
        // Otherwise maybe YES for NSURLAuthenticationMethodDefault and etc.
        return NO;
    }];
    

    You can also add your authorization headers to the subclass, which makes using the connection in various parts of your app very simple.