Experts, I'm a Beginner in IOS 9 / XCODE 7 / Swift 2 Development Kit
I'm trying to create an ios app that simply route to Web Application in HTTPS protocol. Below is my code so far in ViewController.swift
import UIKit
class ViewController: UIViewController {
@IBOutlet var myWebView: UIWebView!
/**
* Function to Display the Web Application initial URL
*/
func loadAppURL(){
let siteAddress = "https://domain:8443/path/to/page"
let url = NSURL (string: siteAddress)
let urlRequest = NSURLRequest(URL: url!)
myWebView.loadRequest(urlRequest)
}
override func viewDidLoad() {
super.viewDidLoad()
loadAppURL()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
While Building my App it shows the below Error Message
2015-10-01 01:05:13.879 Web Page Tester[2947:31838]
NSURLSession/NSURLConnection HTTP load failed
(kCFStreamErrorDomainSSL, -9807)
and if i try building my app instead of "https://domain:8443/path/to/page" with "http://www.apple.com" its works fine.
I can access my web application in Safari and it asks for accepting the security risks. and i accept it and i can access my Application.
Guide me to fix my issues, Thanks in advance.
Finally I fixed it
Xcode will reject un-trusted self signed certificates from servers by default.
we can override this Using NSURLConnection
and can communicate with a self-signed server, since we have the ability to control the authentication through the additional delegate methods which are not available to a UIWebView. So using connection:didReceiveAuthenticationChallenge
we can authenticate against the self signed server.
References
NSURLAuthenticationChallenge Docs , @Lilo Lu's Question
I Resolved My Issue in below steps
Step 1 : Defined a NSURLConnection
in viewDidLoad()
method of my viewController.swift as follows
override func viewDidLoad() {
super.viewDidLoad()
let siteAddress = "https://domain:8443/path/to/page"
let url = NSURL (string: siteAddress)
let urlRequest = NSURLRequest(URL: url!)
let urlConnection:NSURLConnection = NSURLConnection(request: request, delegate: self)!
myWebView.loadRequest(urlRequest)
}
Step 2 : used NSURLConnection delegate methods
func connection(connection: NSURLConnection, canAuthenticateAgainstProtectionSpace protectionSpace: NSURLProtectionSpace) -> Bool{
print("canAuthenticateAgainstProtectionSpace method Returning True")
return true
}
func connection(connection: NSURLConnection, didReceiveAuthenticationChallenge challenge: NSURLAuthenticationChallenge){
print("did autherntcationchallenge = \(challenge.protectionSpace.authenticationMethod)")
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
print("send credential Server Trust")
let credential = NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!)
challenge.sender!.useCredential(credential, forAuthenticationChallenge: challenge)
}else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPBasic{
print("send credential HTTP Basic")
let defaultCredentials: NSURLCredential = NSURLCredential(user: "username", password: "password", persistence:NSURLCredentialPersistence.ForSession)
challenge.sender!.useCredential(defaultCredentials, forAuthenticationChallenge: challenge)
}else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodNTLM{
print("send credential NTLM")
} else{
challenge.sender!.performDefaultHandlingForAuthenticationChallenge!(challenge)
}
}
and that worked !!
You can add the following to your plist
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
In Swift 3.
Step 1. Add NSURLConnectionDelegate
to your viewcontroller, to overwrite methods.
class ViewController: UIViewController, NSURLConnectionDelegate {
Step 2. Override viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
let siteAddress = "https://mysiteaddress"
let url = URL(string: siteAddress)
let urlRequest = URLRequest(url: url!)
let urlConnection:NSURLConnection = NSURLConnection(request: urlRequest, delegate: self)!
webView.loadRequest(urlRequest)
}
Step 3 Overwrite canAuthenticateAgainstProtectionSpace
and didReceive challenge
func connection(_ connection: NSURLConnection, canAuthenticateAgainstProtectionSpace protectionSpace: URLProtectionSpace) -> Bool {
print("\ncanAuthenticateAgainstProtectionSpace method Returning True\n")
return true
}
func connection(_ connection: NSURLConnection, didReceive challenge: URLAuthenticationChallenge) {
print("did autherntcationchallenge = \(challenge.protectionSpace.authenticationMethod)")
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
print("\nsend credential Server Trust\n")
let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
challenge.sender!.use(credential, for: challenge)
}else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPBasic{
print("send credential HTTP Basic")
let defaultCredentials: URLCredential = URLCredential(user: "user", password: "password", persistence:URLCredential.Persistence.forSession)
challenge.sender!.use(defaultCredentials, for: challenge)
}else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodNTLM{
print("\nsend credential NTLM\n")
} else{
challenge.sender!.performDefaultHandling!(for: challenge)
}
}
Thanks Navas Basheer for the original solution! Saved me a ton of time
1- Create category "NSURLRequestCategory" -> after import this category to your bridge file created by xcode (don't forget to let xCode create one if you dont haven't) and put this code :
@implementation NSURLRequest (NSURLRequestCategory)
+ (BOOL)allowsAnyHTTPSCertificateForHost:(NSString *)host
{
return YES;
}
@end
Create your load request UIWebView normally :
webView.delegate = self
let myURL = URL(string: Constants.URL_DOMAINE)
let request = URLRequest(url: myURL!)
webView.loadRequest(request)
Enjoyyy :D
edit Info.plist, Add:
- App Transport Security Settings
- Allow Arbitrary Loads , value is YES
it's work for me, XCode 7.3