I have an HTTPS url. It is loading in iPhone Safari, but didn't work in UIWebView.
Error is:
NSURLConnection/CFURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
How can I fix this problem?
I have explained below how to access https url in UIWebview it will help you clear the problem because it works for me.
Calling http is same as https url.
If, however, you're using a self-signed certificate, it's necessary to add some additional code.Because by default iOS will reject all untrusted https connections.
Restricting untrusted connections is very good default behaviour and any disabling of this is highly risky.So we will show an alert as we're going to bypass the default behaviour.
-(BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace;
-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
These two above methods allows us to provide our own authentication mechanism for trusted connections
#import "ClassCon.h"
// For now, I've hard coded the IP address of my trusted server.
#define TRUSTED_HOST #"192.168.1.2"
#implementation ClassCon {
NSMutableData *contentData;
NSURLConnection *conn;
}
-(void) loadContent {
contentData = [NSMutableData data];
NSString *contentURL = #"our url";
conn = [[NSURLConnection alloc] initWithRequest:
[NSURLRequest requestWithURL:[NSURL URLWithString:contentURL]] delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[contentData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"Bad: %#", [error description]);
ContentResponse *response = [[ContentResponse alloc]initWithRc:-999 andDescr:#"error" andAction:0];
conn = nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *loadedContent = [[NSString alloc] initWithData:
contentData encoding:NSUTF8StringEncoding];
NSLog(#"Loaded content: %#",loadedContent);
}
// ------------ ByPass ssl starts ----------
-(BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:
(NSURLProtectionSpace *)protectionSpace {
return [protectionSpace.authenticationMethod
isEqualToString:NSURLAuthenticationMethodServerTrust];
}
-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:
(NSURLAuthenticationChallenge *)challenge {
if (([challenge.protectionSpace.authenticationMethod
isEqualToString:NSURLAuthenticationMethodServerTrust])) {
if ([challenge.protectionSpace.host isEqualToString:TRUSTED_HOST]) {
NSLog(#"Allowing bypass...");
NSURLCredential *credential = [NSURLCredential credentialForTrust:
challenge.protectionSpace.serverTrust];
[challenge.sender useCredential:credential
forAuthenticationChallenge:challenge];
}
}
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
// -------------------ByPass ssl ends
#end
Hope this helps
Related
I'm using NSURLConnection to connect to a server. It uses basic authorization. This is my code:
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
if ([challenge previousFailureCount] == 0) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSURLCredential *newCredential = [NSURLCredential credentialWithUser:[defaults objectForKey:#"SavedUserName"]
password:[defaults objectForKey:#"SavedPassword"]
persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
}
else {
[self doAlert:#"Cannot acces server" omg:#"Check your login properties"];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#"11111111111");
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#"222222222");
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"333333333333");
}
- (void)checkIfCanLogin{
[conn cancel];
conn = nil;
//setting request and so on
conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[conn start];
}
For first tries is everything ok. - I enter wrong pw, Alert is called. When I enter right password connection is loaded. But when I establish connection, I change password and after that call checkIfCanLogin again, -(void)didRecieveAuth... is not called. That means function returns that server is accessible, but it actually is not.
Any ideas how to improve my code? thanks a lot.
If you look at CredentialsController.m in Apple's AdvancedURLConnections, they illustrate how to purge credentials.
NSURLCredentialStorage *store = [NSURLCredentialStorage sharedCredentialStorage];
assert(store != nil);
for (NSURLProtectionSpace * protectionSpace in [store allCredentials]) {
NSDictionary *userToCredentialMap = [[NSURLCredentialStorage sharedCredentialStorage] credentialsForProtectionSpace:protectionSpace];
assert(userToCredentialMap != nil);
for (NSString * user in userToCredentialMap) {
NSURLCredential *credential = [userToCredentialMap objectForKey:user];
assert(credential != nil);
[store removeCredential:credential forProtectionSpace:protectionSpace];
}
}
The Credentials.m code sample also shows how to purge credentials from the key chain.
I want to know if there is a way to connect to a secured web service (web server requests username and password to connect and return data) with a synchronous way and how can I pass these two parameters in my code, I used this code :
-(void)performRequest{
NSURL * url =[[NSURL alloc] initWithString:#"http://firstluxe.com/api/tags/?display=[id,name]&output_format=JSON"];
NSURLRequest * request = [[NSURLRequest alloc] initWithURL:url];
NSURLConnection * connection =[[NSURLConnection alloc]initWithRequest:request
delegate:self];}
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{ NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
if ([challenge previousFailureCount] == 0)
{
NSURLCredential * cred = [NSURLCredential credentialWithUser: #"userName"
password: #"Password"
persistence: NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:cred forAuthenticationChallenge:challenge];
}
else
{
//You don't have authentication
}
}
-(BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection
{
return YES;
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
//handle errors
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
jsonFromAFNetworking = html;
NSLog(#" html is %# ",html);
}
It returns the value of from the server correctly, but when I do :
- (void)viewDidLoad {
[super viewDidLoad];
[self performRequest];
NSLog(#" jsonFromAFNetworking %#" , jsonFromAFNetworking);
}
I get null value, I know that it's because it is an asynchronous action, but I need to use the new value and I don't know how to do it, how can I tell the code to wait until the [self performRequest]is executed or how to connect to this server by another way?
I am trying to communicate with TSYS payment gateway which has an https server from my iOS application. My original code is given below.
-(void)postRequest:(NSString *)jsonBody{
NSData *requestData = [NSData dataWithBytes:[jsonBody UTF8String]
length:[jsonBody length]];
NSURL *url = [NSURL URLWithString:TSYS_URL];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:[NSString stringWithFormat:#"%d",[requestData length]]
forHTTPHeaderField:#"Content-Length"];
[request setValue:#"*/*" forHTTPHeaderField:#"Accept"];
[request setHTTPBody:requestData];
[[NSURLConnection alloc]initCustomURLWithRequest:request delegate:self ];
}
- (void)connection:(NSURLConnection *)connection
didReceiveResponse:(NSURLResponse *)response{
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
int code = [httpResponse statusCode];
NSLog(#"http error code : %d", code);
[self.receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection
didReceiveData:(NSData *)data {
[self.receivedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"receivedData.length : %d", [self.receivedData length]);
connection = nil;
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error {
connection = nil;
}
The payment gateway url is
#define TSYS_URL #"https://stagegw.transnox.com/servlets/TransNox_API_Server"
And I get this in console
http error code : 404
receivedData.length : 0
When I saw the log, the first port of call was about HTTPS SSL authentication, so I wrote a android project that do POST by trusting all certificate (not ideal, I know), and hurray I was getting correct response. But when I removed the part that enables HttpClient to trust all certificates, I got empty response(in Android).
To make iOS trust all certificate, I added below code
- (BOOL)connection:(NSURLConnection *)connection
canAuthenticateAgainstProtectionSpace:
(NSURLProtectionSpace *)protectionSpace {
//This always returns true
return [protectionSpace.authenticationMethod
isEqualToString:NSURLAuthenticationMethodServerTrust];
}
- (void)connection:(NSURLConnection *)connection
didReceiveAuthenticationChallenge:
(NSURLAuthenticationChallenge *)challenge {
if([challenge.protectionSpace.authenticationMethod
isEqualToString:NSURLAuthenticationMethodServerTrust]){
NSURLCredential *credential = [NSURLCredential
credentialForTrust:challenge.protectionSpace.serverTrust];
[challenge.sender useCredential:credential
forAuthenticationChallenge:challenge];
}
[challenge.sender
continueWithoutCredentialForAuthenticationChallenge:challenge];
}
Still I get the same error.
Ok my questions are
First and foremost, why is this not working? I need to get this
working , so that I can move forward with project. Since my project
is in beginning state, I don't mind if the solution is to trust all
certificates. I somehow need to get server talking.
The type of authentication challenge I am getting is
NSURLAuthenticationMethodServerTrust. Ideally I should get the
server issued certificate and make my NSURLConnection object trust
it. How could I get the certificate file from server?
I got it working at last. In the end, it was not an issue with authentication. Along with the all the code above, I had to pass a header field "User-Agent" with the request. When I passed it I started to get response from the server.
I'm currently experimenting with the twitter streaming api and i'm trying to get a stream with NSURLConnection. As it doesn't work with twitter, i simplified everything and tried to get some source-code out of google's website, but this doesn't work neither.
The connection starts and ends, but without calling the didReceiveData delegate. I'm sure i'm missing something. Hope you guy's can help me!
In the header: #interface ViewController : UIViewController <NSURLConnectionDataDelegate, NSURLConnectionDelegate, NSURLConnectionDownloadDelegate, NSURLAuthenticationChallengeSender>
And in the body:
- (void)viewDidLoad
{
[super viewDidLoad];
NSURLConnection *connection;
NSMutableURLRequest *request;
// Do any additional setup after loading the view, typically from a nib.
request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://www.google.com"]];
[request setHTTPMethod:#"GET"];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
}
- (void)connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *)destinationURL {
NSLog(#"Stream finished.");
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#", dataString);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"Connection failed!");
}
A couple of thoughts.
Your declaration of connectionDidFinishLoading doesn't look right. The standard NSURLConnectionDataDelegate method does not have a destinationURL parameter:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"%s", __FUNCTION__);
}
Given the presence of NSURLAuthenticationChallengeSender, if you're expecting a challenge (which you won't get with Google web site) then you'd obviously handle it accordingly:
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
// For example, if you have a userid/password to use, see if this is the first
// challenge, and then tell NSURLConnection to try using those credentials, and if
// it failed a second time, you might just cancel the authentication challenge.
if (challenge.previousFailureCount == 0) {
NSURLCredential *credential = [NSURLCredential credentialWithUser:kUserID password:kPassword persistence:NSURLCredentialPersistenceForSession];
[challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
} else {
[challenge.sender cancelAuthenticationChallenge:challenge];
}
}
By the way, you do not want to call start method when you use initWithRequest or connectionWithRequest. It's only needed if you do a simple initWithRequest:delegate:startImmediately: and instruct it to not startImmediately.
Anyway, I used the following and it works fine:
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://www.google.com"]];
[NSURLConnection connectionWithRequest:request delegate:self];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"%s", __FUNCTION__);
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%s: %#", __FUNCTION__, dataString);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"%s error=%#", __FUNCTION__, error);
}
Someone said here that it was their SOAP format
NSURLConnection delegate method: didReceiveData not called ...Why ?? (iPhone SDK)
This also may be what you are looking for
NSURLConnection didReceiveData not called
Your NSURLConnection local variable connection is going out of scope at the end of viewDidLoad. Add a property to your ViewController to hold the NSURLConnection variable in scope.
I am trying to get the contents of a webpage that requires a password and user name to access. I am using a NSURLConnection object to get it however when I write the NSMutableData object that is returned to a file all I get is the login page. Normally when you try to load the password protected page when you are not logged in it redirects to the login page however I thought that if I provided valid credentials then this I would be able to view the password protected page. Also I do not know if it is relevant the website is using a microsoft mysql database on an IIS (internet information server).
Note: [protectionSpace authenticationMethod] returns NSURLAuthenticationMethodServerTrust
I am pretty unfamiliar with this so any ideas would be greatly appreciated.
Below is all of the relevant code:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// This method is called when the server has determined that it
// has enough information to create the NSURLResponse.
// It can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.
// receivedData is an instance variable declared elsewhere.
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Append the new data to receivedData.
// receivedData is an instance variable declared elsewhere.
[receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
// release the connection, and the data object
//[connection release];
// receivedData is declared as a method instance elsewhere
//[receivedData release];
// inform the user
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// do something with the data
// receivedData is declared as a method instance elsewhere
NSLog(#"Succeeded! Received %d bytes of data",[receivedData length]);
// release the connection, and the data object
//[connection release];
//[receivedData release];
//Write data to a file
[receivedData writeToFile:#"/Users/matsallen/Desktop/receivedData.html" atomically:YES];
}
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace: (NSURLProtectionSpace *)protectionSpace
{
NSLog(#"The connection encountered a protection space. The authentication method is %#", [protectionSpace authenticationMethod]);
secureTrustReference = [protectionSpace serverTrust];
//SecTrustResultType *result;
//OSStatus status = SecTrustEvaluate(secureTrustReference, result);
//NSLog(#"Result of the trust evaluation is %#",status);
return YES;
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
NSURLCredential *newCredential;
newCredential = [NSURLCredential credentialWithUser:#"username" password:#"password" persistence:NSURLCredentialPersistenceForSession];
newCredential = [NSURLCredential credentialForTrust:secureTrustReference];
// [[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
// [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
receivedData = [[NSMutableData alloc] init];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Create the request.
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:#"https://www.markallenonline.com/secure/maoCoaching.aspx"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
// create the connection with the request
// and start loading the data
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
receivedData = [NSMutableData data];
NSLog(#"Connection succeeded!");
} else {
// Inform the user that the connection failed.
NSLog(#"Connection failed!");
}
}
You need to implement the callback:
-(void) connection:(NSURLConnection *)connection
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
and pass the creds from inside there.
Try using this code instead of what you have:
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
if ([challenge previousFailureCount] == 0) {
NSLog(#"received authentication challenge");
NSURLCredential *newCredential = [NSURLCredential credentialWithUser:#"???????"
password:#"???????"
persistence:NSURLCredentialPersistenceForSession];
NSLog(#"credential created");
[[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
NSLog(#"responded to authentication challenge");
}
else {
NSLog(#"previous authentication failure");
}
}
I use this code, and in my case, I can log in to the protected page.
Try ASIHTTPRequest, this have Basic, Digest and NTLM authentication support.
http://allseeing-i.com/ASIHTTPRequest/
Good luck!