I can do authentication with NSURL and user can assign username and password. However, I got another problem. If I open this, http://html5test.com/ , it also pop up and ask username and password. I got authentication even if it is not supposed to get. I would like to know how to do.
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
if(!_auth)
{
connection_for_auto = [[NSURLConnection alloc] initWithRequest:request delegate:self];
firsttimeonly=TRUE;
[connection_for_auto start];
NSLog(#"Request >> %# and !firsttimeonly",request);
return NO;
}
self.lbl_error.hidden = YES; //hide error message label
return YES;
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
checkTochangeUIalert=TRUE;
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Login"
message:nil
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"OK",#"Auto", nil];
alertView.transform=CGAffineTransformMakeScale(1.0, 0.75);
alertView.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;
[alertView show];
}
I think I have found a way to do. I need to check what kind of authentication method I use.
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic] || [challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodNTLM])
{
.............
}
Related
This seems to be an iOS8 only issue.
I have an app that uses the NSURLConnection delegate. Everything works exactly as it should, except in iOS8 when multiple connections are created and ran successively, an arbitrary number of connections fail to authenticate.
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if (challenge.previousFailureCount == 0)
{
KeychainItemWrapper *itemWrapper = [[KeychainItemWrapper alloc] initWithIdentifier:#"login" accessGroup:nil];
[[challenge sender] useCredential:[NSURLCredential credentialWithUser:[itemWrapper objectForKey:(__bridge id)(kSecAttrAccount)] password:[itemWrapper objectForKey:(__bridge id)(kSecValueData)] persistence:NSURLCredentialPersistenceNone] forAuthenticationChallenge:challenge];
_authenticationChallenged = YES;
}
else
{
[self cancel];
KeychainItemWrapper *itemWrapper = [[KeychainItemWrapper alloc] initWithIdentifier:#"login" accessGroup:nil];
if ([[itemWrapper objectForKey:(__bridge id)(kSecAttrAccount)] isEqualToString:#""]) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Please Log In" message:#"To use this app, please log in" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Log In", nil];
[alertView setTag:2];
[alertView setAlertViewStyle:UIAlertViewStyleLoginAndPasswordInput];
[alertView show];
} else {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Invalid Credentials" message:nil delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Log In", nil];
[alertView setTag:2];
[alertView setAlertViewStyle:UIAlertViewStyleLoginAndPasswordInput];
[alertView show];
}
}
}
In above code is where the issue lies. The else statement is getting called, even though the credentials are correct and work correctly on every other request. This only happens when I create multiple (separate) NSURLConnections at the same time and run them.
Any ideas?
Thanks!
I am creating a rather simple tab-based app with a few UIWebViews. To pass App Store Approval, I need to implement an error if there is no network connection. I'm a beginner, but I tried this and nothing happened.
-(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"Can't connect. Please check your internet Connection"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
I've tried Reachability, but its complicated, and I'm not sure exactly how to implement it into a UIAlertView. Could this code work with tweaking or is it trash?
I suggest you to use delegate methods of webView and implement it in ViewController.
There are mainly three delegate methods of webView.
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
- (void)webViewDidFinishLoad:(UIWebView *)webView
In didFailLoadWithError method you can identify error code using [error code]. You can use any of these as per your requirement.
// Error codes for CFURLConnection and CFURLProtocol
kCFURLErrorUnknown = -998,
kCFURLErrorCancelled = -999,
kCFURLErrorBadURL = -1000,
kCFURLErrorTimedOut = -1001,
kCFURLErrorUnsupportedURL = -1002,
kCFURLErrorCannotFindHost = -1003,
kCFURLErrorCannotConnectToHost = -1004,
kCFURLErrorNetworkConnectionLost = -1005,
kCFURLErrorDNSLookupFailed = -1006,
kCFURLErrorHTTPTooManyRedirects = -1007,
kCFURLErrorResourceUnavailable = -1008,
kCFURLErrorNotConnectedToInternet = -1009,
These error codes are available in CFNetworkError.h. In my application i have used in this way.
if ([error code] == kCFURLErrorNotConnectedToInternet) {
// if we can identify the error, we can present a more precise message to the user.
UIAlertView *alertView=[[[UIAlertView alloc] initWithTitle:APP_NAME message:#"Sorry, there doesn’t seem to be an internet connection." delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles: nil]autorelease];
[alertView show];
}
This is working fine for me.
The viewcontroller which you have assigned delegate for the UIWebView; (in the code of viewcontroller where you have set the webview.delegate=self), you need to commit in the header (.h) file to the UIWebViewDelegate protocol. Only then your method :
-(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
will be triggered. I guess you are missing this otherwise your process is correct.
So, add the UIWebViewDelegate in your .h file.
Hope this will help.
You can check Network Connection using Reachability Code at ViewDidLoad or ViewWillAppear ..Download them using below link
https://github.com/tonymillion/Reachability
Reachability *reach = [Reachability reachabilityForInternetConnection];
NetworkStatus netStatus = [reach currentReachabilityStatus];
if (netStatus != NotReachable)
{
NSLog(#"Async.....Network is Available");
}
else
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Network Error" message:#"No Network Available" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil , nil];
[alertView show];
}
Or You can Put alert on below delegate method of UIWebView
(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
Hope it helps you...!
http://m-qa-www.comixology.net/ this is the url when i am loading it on safari it works great.
but when i load it on uiwebview it does not do anything because of authentication challenge so i added support for authentication it works in for some url but it does not work for this above url.following is the code i am using for it.
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
{
[self showNetworkIndicator];
if (!authed && !conectionAlready) {
authed = NO;
conectionAlready=YES;
urlCon=[[NSURLConnection alloc] initWithRequest:request delegate:self];
return YES;
}
return YES;
}
- (void)webViewDidStartLoad:(UIWebView *)webView
{
NSLog(#"webViewDidStartLoad");
[webView stringByEvaluatingJavaScriptFromString:#"window.alert=null;"];
[self showNetworkIndicator];
authed=NO;
}
-(void) webViewDidFinishLoad:(UIWebView *)webView
{
//conectionAlready=NO;
//[iWebView stringByEvaluatingJavaScriptFromString:#"window.alert=null;"];
NSString *currentURL = webView.request.URL.absoluteString;
NSLog(#"current url %#",currentURL);
URLBar.text=currentURL;
if([iWebView canGoBack])
{
[backButton setEnabled:true];
}
else
{
[backButton setEnabled:false];
}
if([iWebView canGoForward])
{
[fwdButton setEnabled:true];
}
else
{
[fwdButton setEnabled:false];
}
[self hideNetworkIndicator];
}
-(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
NSLog(#"url error ->%#",error.localizedDescription);
[self hideNetworkIndicator];
NSString *errorStr=error.localizedDescription;
if ([errorStr rangeOfString:#"NSURLErrorDomain"].location==NSNotFound) {
UIAlertView *alert=[[UIAlertView alloc] initWithTitle:nil message:#"A server with the specified hostname could not be found." delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
}
}
-(void) showNetworkIndicator
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
}
-(void) hideNetworkIndicator
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
{
authed = YES;
authChallenge=challenge;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Aithentication Required"
message:scRequest.URL.absoluteString
delegate:self cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Log In", nil];
[alert setAlertViewStyle:UIAlertViewStyleLoginAndPasswordInput];
[alert show];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
{
[connection cancel];
conectionAlready=NO;
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if ([response respondsToSelector: # selector (allHeaderFields)]) {
NSDictionary * dictionary = [httpResponse allHeaderFields];
NSLog (# "dictionary =%#", dictionary);
}
if (authed)
{
NSLog(#"remote url returned error %d %#",[httpResponse statusCode],[NSHTTPURLResponse localizedStringForStatusCode:[httpResponse statusCode]]);
NSLog(#"The response is =%#",response);
authed=YES;
NSString *newUrl = [NSString stringWithFormat:#"%#", response.URL];
NSLog(#"newURL%#",newUrl);
scURL =[NSURL URLWithString:newUrl];
scRequest=[NSMutableURLRequest requestWithURL:scURL];
conectionAlready=NO;
[iWebView loadRequest:scRequest];
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[self hideNetworkIndicator];
authed=NO;
conectionAlready=NO;
NSLog(#"oops localizedDescription:%#",error.localizedDescription);
NSLog(#"oops localizedFailureReason:%#",error.localizedFailureReason);
}
- (void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)buttonIndex
{
//NSLog(#"textFieldAtIndex0 %#",[alert textFieldAtIndex:0].text);
//NSLog(#"textFieldAtIndex1 %#",[alert textFieldAtIndex:1].text);
if (buttonIndex==0) {
[[authChallenge sender] cancelAuthenticationChallenge:authChallenge];
}
else
{
[[authChallenge sender] useCredential:[NSURLCredential credentialWithUser:[[alert textFieldAtIndex:0] text] password:[[alert textFieldAtIndex:1] text] persistence:NSURLCredentialPersistenceNone] forAuthenticationChallenge:authChallenge];
}
}
- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection;
{
return YES;
}
Remember the webView is not so competent as a native browser. The native browser handles internally many exception which the webView is not at all competent of. I would suggest if you have the code for the link that you are hitting than try traversing the code and find errors for which the webView doesn't load. I encountered the same issue where some of my JS file were non-responsive. There is no other way you can find bugs in a webView,as it provides limited set of delegated to actually traverse. :)
I am a newbie in the development of iOS applications.
I need to reach different url loaded from a remote XML file,
some of these url require a http basic authentication.
Authentication with NSURLCredential, it works correctly.
Now, I want to require the user to enter their credentials.
When the connection fails I visualize the interface
login UIAlertView with setAlertViewStyle:UIAlertViewStyleLoginAndPasswordInput.
At this point I verify the correspondence
username and password entered by the user with textFieldAtIndex: 0 and 1
but I can and use them for a new connection attempt with NSURLConnection.
Can someone help me?
This is my code:
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
if ([challenge previousFailureCount] == 0)
{
NSLog(#"received authentication challenge");
NSURLCredential *newCredential;
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");
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"Login"
message:#"Enter your username & password"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Login", nil];
[message setAlertViewStyle:UIAlertViewStyleLoginAndPasswordInput];
[message show];
}
}
- (BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView
{
NSString *inputText = [[alertView textFieldAtIndex:0] text];
if( [inputText length] >= 1 )
{
return YES;
}
else
{
return NO;
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"Login"])
{
UITextField *username = [alertView textFieldAtIndex:0];
UITextField *password = [alertView textFieldAtIndex:1];
NSLog(#"Username: %#\npassword: %#", username.text, password.text);
if ([username.text isEqualToString:#"myname"] && [password.text isEqualToString:#"1234"])
NSLog(#"Success");
}
[xmlDataBuffer setLength:0];
}
I'm trying to authenticate users through webserver and calling the following method in my login view button touch to do so.
- (void)connection:(NSURLConnection *)connection
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
NSLog(#"challenge failure %d", [challenge previousFailureCount]);
// Access has failed two times...
if ([challenge previousFailureCount] == 0)
{
//NSLog(#"desc %#",[connection description]);
NSURLCredential *cred = [[[NSURLCredential alloc] initWithUser:userName.text password:passWord.text
persistence:NSURLCredentialPersistenceForSession] autorelease];
[[challenge sender] useCredential:cred forAuthenticationChallenge:challenge];
// need to call new view on correct authentication
[connection release];
}
else {// Answer the challenge
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Authentication error"
message:#"Invalid Credentials" delegate:self
cancelButtonTitle:#"Retry"
otherButtonTitles:nil];
[alert show];
[alert release];
}
}
Is there any status returned after successful authentication so that i may use that status and pass on to next view else display the error.
Jsut Call connectionDidFinishLoading: Method.
Ok, as said in my comment:
Actually the connectionDidFinishLoading: method tells you that you can proceed to the next step.