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];
}
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 using the default classes provided by app to do my networking tasks in my app.
At some point, some of my requests time out (regardless of the reason for the timeout)
I would like to retry some of these requests
I have subclassed the NSURLConnection class and added some parameters to it.
However, in the method "connection:didFailWithError:"
con.retries seems to always be 1, never incremented. Why ?
- (void)connection:(NSURLConnection*) connection didFailWithError:(NSError *)error
{
[[UIApplication sharedApplication]setNetworkActivityIndicatorVisible:NO];
NSLog(#"%#",[NSString stringWithFormat:#"Did recieve error: %#", [error description]]);
NSLog(#"%#",[NSString stringWithFormat:#"%#", [[error userInfo]description]]);
WBURLConnection *con = (WBURLConnection *)connection;
if([con shouldRetryRequest:error]){
con.retries ++;
[con start];
}else{
[con cancel];
[con.data setLength:0];
if(!self.alert){
self.alert = [[UIAlertView alloc]initWithTitle:#"Alert" message:[error localizedDescription] delegate:nil cancelButtonTitle:#"OK" otherButtonTitles: nil];
[self.alert show];
}else {
if(![self.alert isVisible]){
[self.alert show];
}
}
}
}
-(BOOL)shouldRetryRequest:(NSError *)error{
[self.retryCount appendString:[NSString stringWithFormat:#"%#:%ld",error,(long)self.retries]];
LogInfo(#"retries:%#",self.retryCount);
if([error code] == -1004){
return NO;
}
return self.retries<3;
}
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 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])
{
.............
}
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.