How to get cookie from Webserver and maintain it in iOS app? - ios

I would like to to get fetch JSON from http://mycompany.com/page1...http://mycompany.com/page2... On the the webserver side, it requires initial login http://mycompany.com/login, and after that a cookie is maintained for the user. How do I get this behavior with NSURLConnection without having to ask for login every time? Here is the non-working code using NSURLCredential Storage. Do I need to get the cookie from webservice at loging and then send it along with later requests? I struggled with this for some time, So can you please clarify your answer.
- (IBAction)getJSON:(id)sender
{
NSURLCredential *credential = [NSURLCredential credentialWithUser:#"user"
password:#"pass"
persistence:NSURLCredentialPersistenceForSession];
NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc]
initWithHost:#"myCompany.com"
port:0
protocol:#"http"
realm:nil
authenticationMethod:nil];
[[NSURLCredentialStorage sharedCredentialStorage] setDefaultCredential:credential
forProtectionSpace:protectionSpace];
//////////GET JSON//////////////
NSError *error;
NSURL *url = [NSURL URLWithString:#"http://mycompany.com.jsonpage1"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
//I am NOT getting JSON in this delegate
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"%#",responseString);
}

Reading cookies:
refer to Managing HTTP Cookies on iPhone
Setting cookie:
... set dictionary with cookie properties, then:
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:[NSDictionary dictionaryWithObjects:object forKeys:keys]];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
but keep in mind that session cookies can expire on your server

Related

Delete cookies from http header?

I am using a web service with simple header authentication
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
NSString *userName = [_usernameTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];;
NSString *passWord = [_passwordTextfield.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
if ([challenge previousFailureCount] == 0) {
//Creating new credintial
NSURLCredential *newCredential = [NSURLCredential credentialWithUser:userName
password:passWord
persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
}
else {
CommonCode*objCommon=[[CommonCode alloc]init];
[_activityIndicator stopAnimating];
[objCommon showAlert:#"Invalid Password, or no user found with this Email Address"];
}
}
On the logout I am clearing the cokies with
- (void)resetCredintialCache {
NSDictionary *credentialsDict = [[NSURLCredentialStorage sharedCredentialStorage] allCredentials];
if ([credentialsDict count] > 0) {
// the credentialsDict has NSURLProtectionSpace objs as keys and dicts of userName => NSURLCredential
NSEnumerator *protectionSpaceEnumerator = [credentialsDict keyEnumerator];
id urlProtectionSpace;
// iterate over all NSURLProtectionSpaces
while (urlProtectionSpace = [protectionSpaceEnumerator nextObject]) {
NSEnumerator *userNameEnumerator = [credentialsDict[urlProtectionSpace] keyEnumerator];
id userName;
// iterate over all usernames for this protectionspace, which are the keys for the actual NSURLCredentials
while (userName = [userNameEnumerator nextObject]) {
NSURLCredential *cred = credentialsDict[urlProtectionSpace][userName];
[[NSURLCredentialStorage sharedCredentialStorage] removeCredential:cred forProtectionSpace:urlProtectionSpace];
}
}
NSURLCache *sharedCache = [NSURLCache sharedURLCache];
[sharedCache removeAllCachedResponses];
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray *cookies = [cookieStorage cookies];
for (NSHTTPCookie *cookie in cookies) {
[cookieStorage deleteCookie:cookie];
}
}
}
But after logout if I enter the wrong password I am logged in as theprevious user. How do I delete the cookies from the header of the HTTP request?
NSURLRequest has a cachePolicy property, which specifies the caching behaviour of the request.
Set the following cache policy NSURLRequestReloadIgnoringLocalCacheData when making the request like the example bellow will load the data from the url and not from the cache.
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10];
NSURLRequestReloadIgnoringLocalCacheData
Specifies that the data for the URL load should be loaded from the
originating source. No existing cache data should be used to satisfy a
URL load request.
https://developer.apple.com/library/prerelease/mac/documentation/Cocoa/Reference/Foundation/Classes/NSURLRequest_Class/index.html#//apple_ref/c/tdef/NSURLRequestCachePolicy

Prestashop Search API Method in IOS Application

I'm building my first IOS Application and I'm currently integrating my application with my Prestashop website. I already have grabbed a ton of data from the databases, but I'm having less luck using the Search Method from their API.
I have successfully called the REST API and authenticated with the server. I'm getting back a response status code of 200 so everything looks ok with the authentication, however the data I'm receiving from the server is the homepage of my site in HTML form rather than an XML file with the search results.
Below I'll list some of the parts of code in question that I'm using to access the Prestashop server
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"https://www.******.com:443/api/search/?query=%#&language=1",searchTerm]];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
This is the method I use to set up the connection to the Prestashop Server
-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
{
NSLog(#"Test 1.5");
[self clearCookiesForURL];
if([challenge previousFailureCount]==0)
{
NSURLCredential *credential = [NSURLCredential credentialWithUser:#"(I'm omitting the credential key but it does work)" password:#"" persistence:NSURLCredentialPersistenceForSession];
NSLog(#"Credential : %#",credential);
//NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
[challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
} else{
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
}
And this is the method for my authentication. I have all of the other connection methods instantiated (canAuthenticateAgainstProtectionSpace, didReceiveResponse, didReceiveData, etc.) and they are all being called and working fine.
NSLog(#"Data After : %#",responseData);
NSString *tempString;
tempString = [[NSString alloc] initWithData:responseData encoding:NSASCIIStringEncoding];
NSLog(#"String : %#",tempString);
This is the section of code I use to translate the data I get from the server into a string (which i thought was going to be XML but is instead HTML)
Here is a screenshot of the debug log showing that I'm getting an HTML File
Can anybody see what I'm doing wrong here? Any help would be greatly appreciated!

NSURLConnection only authenticates on second attempt

I am trying to load a secure website in a UIWebView my basic approach is to create a NSURL, the n a NSURLRequest, then a NSURLConnection, then to load the NSURLRequest in the UIWebView. When the website is loaded I receive
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
I respond to the challenge sender with
- (void)useCredential:(NSURLCredential *)credential forAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
But after that I get nothing... it just hangs. I put in break points so I know that
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
is being called. If I wait till I am sure that the NSURLConnection is not going to complete then reload the view no authentication challenge is sent but the view will load. I do not have any control over the server. I am open to using AFNetworking, but only if necessary.
The full listing of source code is provided below:
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:
(NSURLAuthenticationChallenge *)challenge
{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
if ([challenge previousFailureCount] == 0)
{
NSString *username = #"username";
NSString *password = #"passsword";
NSURLCredential * cred = [NSURLCredential credentialWithUser:username
password:password
persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:cred forAuthenticationChallenge:challenge];
}
else
{
}
}
-(void)updateCard
{
NSURL * url = [NSURL URLWithString:#"https://ssl.letu.edu/applications/chapelattendance/attendance.html"];
NSURLRequest * request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:50.0];
self.webView =[[UIWebView alloc] initWithFrame:self.bounds];
self.webView.delegate = self;
[self.webView loadRequest:request];
self.connection = [[ NSURLConnection alloc]initWithRequest:request delegate:self];
[self.connection start];
}
Where did I go wrong?
You need to first retrieve the "authentication method" the server is requesting for:
[[challenge protectionSpace] authenticationMethod]
These are the authentication methods (which are string constants) which the expression above returns:
NSURLAuthenticationMethodDefault
NSURLAuthenticationMethodHTTPBasic
NSURLAuthenticationMethodHTTPDigest
NSURLAuthenticationMethodHTMLForm
NSURLAuthenticationMethodNegotiate
NSURLAuthenticationMethodNTLM
NSURLAuthenticationMethodClientCertificate
NSURLAuthenticationMethodServerTrust
Then, you have these options:
If you want to provide the credentials for the given authentication method, you invoke
useCredential:forAuthenticationChallenge:
If you don't want to handle that authentication method yourself and want the system try
to authenticate, you may invoke performDefaultHandlingForAuthenticationChallenge:
which may then fail or not, depending whether the system is capable to handle that type
of authentication and whether it can find credentials in well known storages.
If you cant handle that authentication method -- say authentication method
NSURLAuthenticationMethodNTLM for example -- you can skip this protection
space and try another protection space if another one
exists in this authentication challenge. Then you may possibly get an
authentication method NSURLAuthenticationMethodHTTPBasic which you
are capable to handle.
In order to reject the current protection space you send method
rejectProtectionSpaceAndContinueWithChallenge: to the
authentication challenge sender. Then, NSURLConnection will send
once again willSendRequestForAuthenticationChallenge: to your
delegate with another protection space if any further exists.
You may try to continue without providing credentials at all.
Likely, the authentication will fail. You can try it through
sending message continueWithoutCredentialForAuthenticationChallenge:
to the authentication challenge sender.
And finally, you can cancel the request through canceling the
authentication challenge: send cancelAuthenticationChallenge: to
the authentication challenge sender.
Note: NSURLAuthenticationMethodHTTPBasic and NSURLAuthenticationMethodHTTPDigest authentication methods can be handled with the same NSURLCredential object created with +credentialWithUser:password:persistence:
If anyone comes along and has the same problem be sure I want to share the solution I found. Use AFNetworking.
Here is the revised code:
-(void)updateCard
{
if(!self.webView)
{
self.webView =[[UIWebView alloc] initWithFrame:self.bounds];
self.webView.delegate = self;
}
NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults];
NSString *username = #"username";
NSString *password = #"password";
NSURL *url = [NSURL URLWithString:#"https://ssl.letu.edu/"];
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL: url];
[client setAuthorizationHeaderWithUsername:username password:password];
NSMutableURLRequest *request = [client requestWithMethod:#"GET" path:#"applications/chapelattendance/attendance.html"
parameters:nil];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
[self.webView loadRequest:request];
}
failure: ^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"Could not load chapel attendance");
}];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest];
operation.securityPolicy.allowInvalidCertificates = YES;
You need to send the username and password combination with the http header to authenticate the request while sending the same.
NSData *authData = [#"username:password" dataUsingEncoding:NSASCIIStringEncoding];
NSString *authorization = [NSString stringWithFormat:#"Basic %#", [authData base64Encoding]];
[mutableRequest addValue:authorization forHTTPHeaderField:#"Authorization"];

Issue with OAuth authentication for the new Basecamp Api using OAConsumer

My code looks something like this :
OAConsumer *consumer = [[OAConsumer alloc] initWithKey:#"my_ClientID"
secret:#"my_Secret"];
NSURL *url = [NSURL URLWithString:#"https://launchpad.37signals.com/authorization/token"];
OAMutableURLRequest *request = [[OAMutableURLRequest alloc] initWithURL:url
consumer:consumer
token:nil // we don't have a Token yet
realm:nil // our service provider doesn't specify a realm
signatureProvider:nil]; // use the default method, HMAC-SHA1
[request setHTTPMethod:#"POST"];
NSLog(#"USER URL : %#",[request URL]);
OADataFetcher *fetcher = [[OADataFetcher alloc] init];
[fetcher fetchDataWithRequest:request
delegate:self
didFinishSelector:#selector(requestTokenTicket:didFinishWithData:)
didFailSelector:#selector(requestTokenTicket:didFailWithError:)];
.
- (void)requestTokenTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data {
if (ticket.didSucceed) {
NSString *responseBody = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
OAToken *requestToken = [[OAToken alloc] initWithHTTPResponseBody:responseBody];
NSLog(#"%#",requestToken);
}
}
My Delegate method never gets a (ticket.didSucceed) Success.
Can someone tell me what I am missing here?
Thanks
It looks like you are trying to have the user authorize your app and generate the token for the first time. For this, you're using the wrong URL. From the 37Signals API:
Your app requests authorization by redirecting your user to Launchpad:
https://launchpad.37signals.com/authorization/new?type=web_server&client_id=your-client-id&redirect_uri=your-redirect-uri
The URL you are using is for getting the access token from the verification code.

Using user authentication/sessions with Django and ASIHttpRequest

I am trying to make a basic authentication system in iOS that sends a POST to Django and on the Django side authenticates the user and starts a session. Right now I am able to send the user information by passing the values as data in the URL and authenticating it, but how do I retrieve the session data or cookie from the Django response? When I try to store or print out the cookie, it tells me the array is empty. I have tried both request.requestCookies and request.responseCookies.
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:#"test_user", #"username", #"pass", #"password", nil];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://127.0.0.1:8000/login/"]];
NSError *error;
NSData *data = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
if ( error ) {
NSLog( #"ERROR - %#", error.localizedDescription );
} else {
__block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request addRequestHeader: #"Content-Type" value:#"application/json; charset=utf-8"];
[request appendPostData:data];
[request setRequestMethod:#"POST"];
[request setCompletionBlock:^{
UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:#"Login"
message:#"Login was sent"
delegate:nil
cancelButtonTitle:nil
otherButtonTitles:#"Ok", nil];
[alerView performSelectorOnMainThread:#selector(show) withObject:nil waitUntilDone:NO];
NSLog(#"RESPONSE: %#", [[NSString alloc] initWithData:request.responseData encoding:NSUTF8StringEncoding]);//, [request.requestCookies objectAtIndex:0]);
NSLog(#"COOKIE: %#", [request.requestCookies objectAtIndex:0]);
[ASIHTTPRequest addSessionCookie:[request.requestCookies objectAtIndex:0]];
}];
Okay, so I resolved this issue and it turns out that on the server side I was putting in the data but not officially logging in with Django (was not returning the proper cookies) which meant my app was not receiving the proper header.

Resources