2

For some background info, the webpage I'm trying to display is a web app currently being hosted on AWS's EC2. The backend is Python w/ Flask and the frontend is just simple HTML/CSS. The URL has HTTP, as it isn't secured with HTTPS yet. When the url for this webpage is opened, the first thing the browser asks is for login credentials (the browser asks, not the website). This page does load in mobile Safari on my iPhone, and Safari does successfully ask for the credentials. If I enter them in correctly, it will correctly load the page.

So I've tried both Allow Arbitrary Loads under App Transport Security Settings as well as a customized Exception Domain with the following keys:

App Transport Security Settings                         Dictionary
Exception Domains                                       Dictionary
    my website URL                                      Dictionary
        NSIncludesSubdomains                            Boolean (YES)
        NSExceptionAllowsInsecureHTTPLoads              Boolean (YES)
        NSThirdPartyExceptionAllowsInsecureHTTPLoads    Boolean (YES)
        NSExceptionMinimumTLSVersion                    String (TLSv1.0)
        NSExceptionRequiresForwardSecrecy               Boolean (YES)

However, whenever I launch the app on the simulator all I'm getting back is a white screen (can post screenshot if needed).

Here's my code in ViewController.swift:

import UIKit

class ViewController: UIViewController {

     @IBOutlet var WebView: UIWebView!

     override func viewDidLoad() {
         super.viewDidLoad()
         let url = NSURL(string: "My URL inserted here")
         let request = NSURLRequest(URL: url!)
         WebView.loadRequest(request)
     }
     override func didReceiveMemoryWarning() {
         super.didReceiveMemoryWarning()
     }
 }

If I use Allow Arbitrary Loads, when I look in the output box, it does not say "App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file." When I configure the Exception Domain correctly (with Allow Arbitrary Loads removed) it won't give me the message either. Only sometimes when I change around the settings using Exception Domain (again, with Allow Arbitrary Loads removed) do I get this output.

I'm starting to think the issue goes beyond security, and any advice or steps I could take to try and fix this issue would be much appreciated, thanks!

Rohan
  • 93
  • 1
  • 11
  • You mentioned that the browser asks for authentication on the page - are you using Basic Authentication for this? If so the username and password pop up on Mobile Safari will not happen in a UIWebView by default. I would say the best way would be to include the username and password in the URL like: http://username:password@example.com – julianwyz Jul 08 '16 at 14:47
  • @wyzkid207 I can't say I've heard of Basic Authentication (absolute beginner dev, still learning a lot everyday haha). I just tried the approach you mentioned and it didn't work. Is there a way to make it so that the webview does show some authentication prompt? Or as a different sidenote, is there a way to specify which browser UIWebView loads up, like can I make it so that it opens Safari, Chrome, etc? Thanks :) – Rohan Jul 08 '16 at 15:05
  • If you want to open the URL in mobile safari you can refer to this SO: http://stackoverflow.com/questions/2899699/uiwebview-open-links-in-safari?rq=1 (And this may be a stupid question - but can you load like "https://apple.com" with the code you have currently?) – julianwyz Jul 08 '16 at 15:09
  • @wyzkid207 Awesome, I'll check it out. And yeah, regular websites will load, regardless of whether I use HTTP or HTTPS in their URL (provided Allow Arbitrary Loads is enabled) – Rohan Jul 08 '16 at 15:19

1 Answers1

2

The white screen is a bit odd, assuming that a 401 would result in a standard error page, but maybe the server set up a white page for this. My guess is that setting username and password directly in the URL doesn't work, you shouldn't do that anyways, but instead rely on WKWebView's webView:didReceiveAuthenticationChallenge: delegate method.

Here's some sample code hopefully working/helping:

#import "ViewController.h"
@import WebKit;

@interface ViewController () <WKNavigationDelegate>

@property (nonatomic, strong) WKWebView *webView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:[WKWebViewConfiguration new]];
    self.webView.navigationDelegate = self;
    [self.view addSubview:self.webView];
    [self.webView setTranslatesAutoresizingMaskIntoConstraints:NO];

    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[_webView]-0-|"
                                                                     options:NSLayoutFormatDirectionLeadingToTrailing
                                                                     metrics:nil
                                                                       views:NSDictionaryOfVariableBindings(_webView)]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[_webView]-0-|"
                                                                      options:NSLayoutFormatDirectionLeadingToTrailing
                                                                      metrics:nil
                                                                        views:NSDictionaryOfVariableBindings(_webView)]];
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    NSURL *target = [NSURL URLWithString:@"http://yourhost.com/possiblePage.html"];
    NSURLRequest *request = [NSURLRequest requestWithURL:target];
    [self.webView loadRequest:request];
}

- (void)webView:(WKWebView *)webView 
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge 
                completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {

    NSURLCredential *creds = [[NSURLCredential alloc] initWithUser:@"username" 
                                                          password:@"password" 
                                                       persistence:NSURLCredentialPersistenceForSession];
    completionHandler(NSURLSessionAuthChallengeUseCredential, creds);
}

@end

This is basically the implementation file of a simple ViewController (like from the single view template of XCode). It also shows you how you can add a WKWebView. Definitely make sure to check out all the delegate methods and such so you know what the thing can do for you.

Obviously, password and username have to be set somehow, I guess you can use a simple alert popup to have the user enter this info (this would be similar to Safari in principle). For the first test you can just hardcode it. Also note I set a sample subpage there, just use the exact same URL you would usually use on a desktop browser. Oh, and since the server doesn't have SSL, you need to allow arbitrary loads.

Edit:

RPM gave a good related comment below (thanks) that I had not originally thought about. The method may (actually will very likely) be called multiple times. This ultimately also depends on the website you load. RPM's explanation for why a site may appear plain white is spot on.

In any way, the webView:didReceiveAuthenticationChallenge:completionHandler: method above is just a simple example assuming you know the PW and username. Generally it will be more complex and you shouldn't just open an input dialog every time it is called for the user to enter credentials. As a matter of fact, the provided challenge offers ways to set a specific call to this delegate method into relation to previous calls. For example, it has a proposedCredential property that may already have been set. (Whether that's the case for loading multiple resources I don't know on the top of my head, just try that out.) Also, check its previousFailureCount, etc. A lot of this may depend on the site you load and what it needs to get.

Gero
  • 4,394
  • 20
  • 36
  • Thanks @gero for this. This was a good answer ! I think it is important to use WKWebView and not UIWebView. The reason is that for every resource requested by the webpage the delegate method is called to get the credentials. That doesn't happen if you use UIWebView. With UIWebView you can provide the credentials only for the page request and not for all the items in the page - thats why my page was showing up but it was blank ! – RPM Mar 08 '18 at 04:40
  • Hey, kudos for that info @RPM. I extended the answer a bit (even though it is older by now). Glad I could help you out. – Gero Mar 09 '18 at 07:50