UIWebView not save cookies - ios

I use UIWebView that users login in accounts. Users may login with facebook account. He is click button Facebook and opens UIWebView. After login UIWebView close and users may use your personal account. But when I close my app and open it again users not login. UIWebView not save cookies.
I found this answer https://stackoverflow.com/a/26006163
And added this code in my app. This only works temporarily. I close my app and open through hours it again users not login.
I tried to change this line
[cookieProperties setObject:[[NSDate date] dateByAddingTimeInterval:2629743] forKey:NSHTTPCookieExpires];
to this
[cookieProperties setObject:[[NSDate date] dateByAddingTimeInterval:100*12*30*60*60] forKey:NSHTTPCookieExpires];
But it did not help me.

Cookies are temporary and it doest miraculously come back when you relaunch the app.
you need to save the cookies or the credential in keychain and get it back once you relaunch.

I had such a problem. I tried many ways. I decided use dirty hack :D
That's my way:
When I was getting NSHTTPURLResponse for facebook (or else) i save request url to NSUserDefaults:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
if ([[httpResponse URL].absoluteString isEqualToString:#"http://www.simple.com/"])
{
[[NSUserDefaults standardUserDefaults] setURL:self.url forKey:#"urlLogin"];
[self dismissViewController];
}
}
And when I open my App i use NSURLRequest with my stored url:
NSURLRequest *request = [NSURLRequest requestWithURL:[[NSUserDefaults standardUserDefaults] URLForKey:#"urlLogin"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:3.0];
[NSURLConnection connectionWithRequest:request delegate:self];

Related

LinkedIn Login saves the credentials in iOS

I am using LinkedIn to share the images. I need to login at first time after that it needs to save the LinkedIn credentials in the app. When i run the app next time again LinkedIn Login will display. How can i solve this problem.
I have saved the access token and passing that value, but still i am getting the error message like this "The partner did not properly implement the authentication protocol"
When you fetch the accessToken:
self.accessToken = [[OAToken alloc] initWithHTTPResponseBody:responseBody];
Save it in the user defaults so next time you can use it to avoid re-login:
[[NSUserDefaults standardUserDefaults] setObject:responseBody forKey:#"accessToken"];
Access back the accessToken:
NSString* accessToken = [[NSUserDefaults standardUserDefaults] valueForKeyPath:#"accessToken"];
OAMutableURLRequest *request =[[OAMutableURLRequest alloc] initWithURL:url consumer:self.consumer token:[[OAToken alloc] initWithHTTPResponseBody:accessToken]];

ios Facebook integration error when logged out and logged in

I am trying to use Facebook integration into my app. I use the following code to log in.
After i am logged in and when i log out the app relaunches completely from the beginning and also each time the permission is asked. I only want it to ask permission in the first time when i login with a particular user. But it asks always when i log out and try to login back with the Facebook button.
- (IBAction)facebook:(id)sender
{
FBLoginView *loginView=[[FBLoginView alloc]init];
loginView.delegate=self;
loginView.readPermissions = #[#"first_name",
#"last_name",
#"location",
#"id",
#"access_token",
#"email"];
NSArray* permissions = [NSArray arrayWithObjects: #"email", nil];
loginView.readPermissions = #[#"email"];
loginView.readPermissions=permissions;
[FBSession openActiveSessionWithAllowLoginUI:YES];
[FBRequestConnection
startForMeWithCompletionHandler:^(FBRequestConnection *connection,
id<FBGraphUser> user1,
NSError *error)
{
if (!error)
{
firstname=user1.first_name;
lastname=user1.last_name;
city=[user1.location objectForKey:#"name"];
email=user1[#"email"];
fbid=user1.id;
Loggedin=#"Y";
[[NSUserDefaults standardUserDefaults]setObject:Loggedin forKey:#"token"];
[[NSUserDefaults standardUserDefaults]synchronize];
}
NSURL *url = [[NSURL alloc]initWithString:[NSString stringWithFormat:#"%#action=currfbuser&email=%#&fb_id=%#",MainURL,email,fbid ]];
NSError *errors;
NSData *data = [NSData dataWithContentsOfURL:url];
NSDictionary *json = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&errors];
status = json[#"status"];
user = json[#"user"];
if ([status isEqualToString:#"success"])
{
[self performSegueWithIdentifier: #"LogIN" sender: self];
}
else if (!([fbid isEqualToString:#""]))
{
[self performSegueWithIdentifier: #"Facebooksegue" sender: self];
}
NSLog(#"%#",firstname);
NSLog(#"%#",lastname);
NSLog(#"%#",city);
NSLog(#"%#",email);
NSLog(#"%#",fbid);
}];
}
The following code i have used to log out.
- (IBAction)Logout:(id)sender
{
_DetailsView.hidden=YES;
_fade.hidden=YES;
y=0;
Loggedin=#"N";
user=nil;
NSHTTPCookieStorage* cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray* facebookCookies = [cookies cookiesForURL:[NSURL URLWithString:#"http://login.facebook.com"]];
for (NSHTTPCookie* cookie in facebookCookies) {
[cookies deleteCookie:cookie];
}
[FBSession.activeSession closeAndClearTokenInformation];
[[NSUserDefaults standardUserDefaults]setObject:Loggedin forKey:#"token"];
[[NSUserDefaults standardUserDefaults]setObject:user forKey:#"user"];
[[NSUserDefaults standardUserDefaults]synchronize];
[self.navigationController popToRootViewControllerAnimated:YES];
}
This is the first time i am integrating Facebook. So i am not much kind of sure about the code i am using.
The user data fetching is working perfectly fine. The problem is that the app asks for permission each time and if i press Ok or skip for permission both does the same thing that is the app relaunches when i click ok or skip.
The output i obtained has been uploaded in youtube. Please check the following link.
http://youtu.be/ki7BXr8dXmw
I been stuck with this and can't move forward coz of this bug.
Please help me with this and i can give out 50 bounty for the solution when the bounty is available.
Thank you.
Well i have few suggestions. Here you are always opening FB session with login UI.
[FBSession openActiveSessionWithAllowLoginUI:YES];
That is not required always. Once you authorized the user and you got the required permission you no longer needed the login UI. So how will you decide my user is authorized or not?? Just try to login on behalf of user without Login UI (fallback login)
[FBSession openActiveSessionWithAllowLoginUI:NO]; // Should go in viewDidLoad or applicationDidFinishLaunching
If this login attempt success(Taking the cached token), well you have an active FBSession. Now the actual facebook api usage comes. Do a simple check
if (FBSession.activeSession.isOpen)
{
[self getFacebookFriends];
}
else
{
// User is not logged in
[FBSession openActiveSessionWithAllowLoginUI:YES];
}

Create a cart with Magento api and iOS

In my app I will to add an object to a remote Magento cart. So my app has a viewController in which I select the product I want, when I tap on the product it presents me another viewController in which I can read the details of the products. Now I put a button in this viewController to add the product to a cart.
I tried the Magento e-commerce on my browser and I saw that when I click on the button "Add to Cart" it sends an http request to the server with this address:
http://54.204.6.246/magento8/checkout/cart/add/uenc/aHR0cDovLzU0LjIwNC42LjI0Ni9tYWdlbnRvOC9zcGVjaWFsLXNhbGVzLmh0bWw,/product/1/form_key/Zqmpp3fnpuTtxI4b/
In this way I put the product in the remote cart of Magento. Now I want to do the same things with my iOS app, so I wrote the following code:
#import "CreateCarriage.h"
#import "NSData+Base64.h"
#implementation CreateCarriage{
NSMutableData *datas;
}
- (void)createCarriageWithProductID:(NSString *)productID {
NSString *addProductLink = [NSString stringWithFormat:#"http://54.204.6.246/magento8/checkout/cart/add/uenc/aHR0cDovLzU0LjIwNC42LjI0Ni9tYWdlbnRvOC9zcGVjaWFsLXNhbGVzLmh0bWw,/product/%#/form_key/Zqmpp3fnpuTtxI4b/", productID];
[self sendRequestToURL:addProductLink withMethod:#"GET"];
}
- (id)sendRequestToURL:(NSString *)url withMethod:(NSString *)method {
NSURL *finalUrl;
if ([method isEqualToString:#"GET"]) {
finalUrl = [NSURL URLWithString:url];
} else {
NSLog(#"Metodo non previsto");
}
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:finalUrl];
[request setHTTPMethod:method];
NSString *authStr = #"user:password";
NSData *authData = [authStr dataUsingEncoding:NSUTF8StringEncoding];
NSString *authValue = [NSString stringWithFormat:#"Basic %#", [authData base64EncodedString]];
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
// [request setValue:#"x-www-form-urlencoded charset=utf-8" forHTTPHeaderField:#"Content-type"];
NSLog(#"%#", request);
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
if (connection) {
[connection start];
}
return connection;
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
datas = [[NSMutableData alloc]init];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#"%#", [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]);
[datas appendData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"Oggetto aggiunto al carrello");
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"%#", error);
}
#end
But when I run the app it shows me this:
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>401 Authorization Required</title>
</head>
<body>
<h1>Authorization Required</h1>
<p>This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g., bad password), or your browser doesn't understand how to supply the credentials required.</p>
<hr>
<address>Apache/2.2.15 (Red Hat) Server at 54.204.6.246 Port 80</address>
</body>
</html>
What's wrong in my code? The user and the password I set in the code are correct indeed if I try them on a normal browser they works.
Magento does not support HTTP Basic Authentication. The URL which you are using above will add product with id=1 to the "current" user's shopping cart, where the "current" user is identified by session cookies. Your iOS native app will not maintain cookies, so the above snippet will not work even if you solve the HTTP authentication problem.
The HTTP authentication error is most likely due to an incorrect server configuration/username-password. Check your Apache configuration (http://httpd.apache.org/docs/2.2/mod/mod_auth_basic.html). The reason it is working in your browser is because it accepts cookies and thus, Magento is able to maintain your session.
If you want to authenticate your Magento customers, you will have to use Magento's APIs. You can use either the SOAP API (www.magentocommerce.com/api/soap/introduction.html) or the REST API (www.magentocommerce.com/api/rest/introduction.html).
Both of them however have their own set of problems. You might want to have a look at MobStac's iOS SDK for Magento. In addition to customers' cart syncing between desktop and mobile, it also has support for fetching catalog information and payments. Visit http://developer.mobstac.com/ for more details. Disclaimer: I work for MobStac.

Steps to use SharePoint Rest interfaces in iOS

I am developing an app for SharePoint online and wanted to use the SharePoint Rest interfaces in my ios app. Can Some one please tell me the steps to use SharePoint Rest interfaces in iOS
I got it, below are the steps to be followed:
Include RestKit in your ios app.
Create a UIView in your home screen and load the login page.
load http: //server name/Pages/default.aspx in the UIWebView
In webViewDidFinished method find out the Fed Auth token and append it with the request URL
- (void)webViewDidFinishLoad:(UIWebView *)webView {
//Retrive HTTPOnly Cookie
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray *cookiesArray = [storage cookies];
//Search for Fed Auth cookie
for (NSHTTPCookie *cookie in cookiesArray) {
if ([[cookie name] isEqualToString:#"FedAuth"]) {
/*** DO WHATEVER YOU WANT WITH THE COOKIE ***/
NSLog(#"Found FedAuth");
NSURL *url=[NSURL URLWithString:#"http://my server/_vti_bin/listdata.svc"];
RKClient *client = [RKClient clientWithBaseURL:url];
client.requestQueue.requestTimeout = 10;
client.cachePolicy = RKRequestCachePolicyNone;
client.authenticationType = RKRequestAuthenticationTypeHTTPBasic;
client.username = #"username";
client.password = #"Password";
NSString *cookieVale=[cookie value];
NSString *getResourcePath=[#"?" stringByAppendingFormat:#"%#",cookieVale];
[client get:getResourcePath delegate:self];
break;
}
}
}
And here you can find the response.
- (void)request:(RKRequest *)request didLoadResponse:(RKResponse *)response {
id xmlParser = [[RKParserRegistry sharedRegistry] parserForMIMEType:RKMIMETypeXML];
NSError *error = nil;
id parsedResponse = [xmlParser objectFromString:[response bodyAsString] error:&error];
RKLogInfo(#"Parsed response : %#, error:%#",parsedResponse,error);
if ([response isSuccessful]) {
NSLog(#"%d",[response isCreated]);
// Response status was 200..299
if ([response isCreated] && [response isJSON]) {
// Looks like we have a 201 response of type application/json
RKLogInfo(#"The JSON is %#", [response bodyAsJSON]);
}
} else if ([response isError]) {
// Response status was either 400..499 or 500..599
RKLogInfo(#"Ouch! We have an HTTP error. Status Code description: %#", [response localizedStatusCodeString]);
}
}
The self accepted answer lost me lots of hours of trials and errors. It omits some key aspects like the fact that you also need to grab the rtFa cookie. And what's up with client.username = #"username" and client.password = #"Password" provided in the users code. What is that? Note that the client does not know the username or password at any moment...
AAAnyway, below is a great article which will guide you in the right direction:
http://www.codeproject.com/Articles/571996/Development-of-iPhone-client-application-for-Share
And this describes how to get the cookies without using a UIWebView
http://allthatjs.com/2012/03/28/remote-authentication-in-sharepoint-online/
Send the FedAuth cookie with all your subsequent Requests.
Once authenticated, you can call the REST API, documentation here:
http://msdn.microsoft.com/en-us/library/fp142385(v=office.15).aspx#bk_determining
When the user finish the sign in process towards a Office365 Sharepoint instance, the web view will be redirected in several steps. As one of the final steps before loading the actual Sharepoint web site, the web view will be asked to load "about:blank".
Detect when you web view starts loading "about:blank" and you know when the user finished the sign in process and can close the web view. Example code below.
// Load page in web view
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSLog(#"WebView should start loading %#", request.URL.absoluteString);
// Detect that the user finished the sign in process
if ([request.URL.absoluteString isEqualToString:#"about:blank"]) {
// Do your stuff here
return NO;
}
return YES;
}
The Sharepoint instance will also set the FedAuth cookie if the authentication was successful. The cookie must be included in future requests to the server.
You do not have to append the cookie manually, this will be taken care of by the URL loading system as long as the cookies has been accepted and stored in the NSHTTPCookieStorage and you are sending the request to the same server.
From Apple documentation
The URL loading system automatically sends any stored cookies
appropriate for an NSURLRequest. unless the request specifies not to
send cookies. Likewise, cookies returned in an NSURLResponse are
accepted in accordance with the current cookie acceptance policy.

iOS - problems with NSURLAuthenticationChallenge - connection successful but can't access server

I am using NSURLAuthenticationChallenge to log in to a webserver through my app. All the server requires is a username and a password. Here is what's happening:
(1) Ping server with POST message containing a User-Agent string in the HTML header
(2) Server responds with an authentication challenge which is detected by the didReceiveAuthenticationChallenge delegate method
(3) Respond by sending a challenge response using username and password:
NSURLCredential *cred = [[NSURLCredential alloc] initWithUser:unameTextField.text
password:pswdTextField.text
persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:cred forAuthenticationChallenge:challenge];
(4) If username/password are correct, delegate method connectionDidFinishLoading gets called, detecting that the challenge response was accepted by the server. User is now logged in and can send/receive messages from the server. (If username/password are incorrect, delegate method didFailWithError gets called and user is shown an alert.)
Here's where it's going wrong: the very first time I open my Xcode project and run the app and attempt to login with the correct username/password, there is a time lag of 10-15 seconds between steps 3 and 4. And then even after connectionDidFinishLoading is called, when I send messages to the server requesting files it responds by sending me the HTML login page which is the default behavior for unauthenticated requests...so it seems as though I'm not logged in after all.
If I stop and then run the app again there is no lag and everything works fine.
EDIT: I solved the above problem by clearing the URLCache, all cookies and all credentials before each login attempt. Code for these 3 methods is below:
- (void)clearCookiesForURL
{
NSURL *loginUrl = [NSURL URLWithString:#"https://www.MYURL.com"];
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray *cookies = [cookieStorage cookiesForURL:loginUrl];
for (NSHTTPCookie *cookie in cookies)
{
[cookieStorage deleteCookie:cookie];
}
}
- (void)eraseCredentials
{
NSString *urlString = #"www.MYURL.com";
NSURLCredentialStorage *credentialsStorage = [NSURLCredentialStorage sharedCredentialStorage];
NSDictionary *allCredentials = [credentialsStorage allCredentials];
if ([allCredentials count] > 0)
{
for (NSURLProtectionSpace *protectionSpace in allCredentials)
{
if ([[protectionSpace host] isEqualToString:urlString])
{
NSDictionary *credentials = [credentialsStorage credentialsForProtectionSpace:protectionSpace];
for (NSString *credentialKey in credentials)
{
[credentialsStorage removeCredential:[credentials objectForKey:credentialKey] forProtectionSpace:protectionSpace];
}
}
}
}
}
- (void)eraseURLCache
{
NSURL *loginUrl = [NSURL URLWithString:#"https://www.MYURL.com"];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:loginUrl];
[[NSURLCache sharedURLCache] removeCachedResponseForRequest:urlRequest];
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
[[NSURLCache sharedURLCache] setDiskCapacity:0];
}
Another problem: if I wait for a long time between sending message requests to the server while the app is running, the server thinks I've logged out and exhibits the same behavior described above.
EDIT: this 2nd problem remains unsolved. Additional information - it appears that the magic time lag number is 10 seconds. In other words, if I wait more than 10 seconds after the server has authenticated me to request a file from the server, it doesn't recognize my request and sends me the web login page instead, just as it would do for an unauthenticated request.
Any idea what's going on? And no, I can't simply load the webserver login page inside my app, because that doesn't meet the requirements for this project.

Resources