Can always login - iphone

A colleague and me have stumbled upon bug in both of our codes. We happen to both be working on a login page. I am using the networking library AFNetworking to connect to an outside source, which tells if the user has actually registered. The friend likewise (but without any outside library). (Code is for ios.)
We are both running into the same problem: after making a valid call, everything goes as expected. But if we make another call that is invalid (e.g., wrong username and/or password) I am still able to login.
Why? We are not saving any information.
Here is some code:
BasicAuth * manger = [BasicAuth sharedManager];
manger = nil;
[[BasicAuth sharedManager] setUsername:#"bad_username" andPassword:#"wrong"];
[[BasicAuth sharedManager] getPath:#"/users/tokens"
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"operation = %#", [responseObject description]);
NSError *error = nil;
/*
*/
if (error) {
NSLog(#"Error serializing %#", error);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (operation.response.statusCode == 500) {
} else {
NSData *jsonData = [operation.responseString dataUsingEncoding:NSUTF8StringEncoding];
// NSString *errorMessage = [ objectForKey:#"error"];
NSLog(#"We have an issue %#", [error description]);
}
}]; return YES;
If I call this same code but with a correct username/password AND THEN call the above code, then I can still login in and the information I get back is the same as when I sent the "good" request. Also, when I try to make login requests using curl from my laptop I do not run into the same issues, which is making me think that, for some reason, the information being sent is not being updated. But I can't see how or why. Again, this is whether 3rd party library is being used or not.
Thoughts, suggestions?
note: BasicAuth (see above) is a subclass of AFHTTPCLIENT

Your server may be sending some cookie and iOS is store it.
Try to delete the cookies before setting the new username and password.
Here you have a code snippet that deletes all cookies. Keep in mind that in iOS the cookies are application private, so deleting them is not going to affect other apps.
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray *cookies = [storage cookies];
for (NSHTTPCookie *cookie in cookies)
{
[storage deleteCookie:cookie];
}

Related

POST Request with AFNetworking 2.0 not working, but working in HTTP Request tester

I've just started using the new AFNetworking 2.0 API having used the previous versions for a while now. I'm trying to do a bog standard http POST request, but sadly I'm not doing too well. This is my current code:
AFHTTPRequestOperationManager *operationManager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = #{#"username" : self.usernameField.text,
#"password" : self.passwordField.text};
[operationManager POST:#"https:URL GOES HERE" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", [responseObject description]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
Now this returns a JSON of (NULL) and doesn't give me a status code like 404 or something (incidentally how do we attain the status code when using AFN 2.0?). However, when I try the information with a web app like apikitchen.com which tests the HTTP Post request for me, it works when I put the username and password in the param field. So really my question is, why don't the parameters in the AFN 2.0 parameter property act in the same way as the parameters in the web app? And more generally why aren't the post request parameters working for me in AFN 2.0?
Thanks for the help in advance,
Mike
EDIT: I'm struggling with the implementation of the suggested fix. My Post method now looks like this, but It doesn't make sense to me right now.
AFHTTPRequestOperationManager *operationManager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = #{#"username" : self.usernameField.text,
#"password" : self.passwordField.text};
operationManager.requestSerializer.queryStringSerializationWithBlock =
^NSString*(NSURLRequest *request,
NSDictionary *parameters,
NSError *__autoreleasing *error) {
NSString* encodedParams = form_urlencode_HTTP5_Parameters(parameters);
return encodedParams;
};
[operationManager POST:#"URL HERE" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", [responseObject description]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
Now this returns a JSON of (NULL) and doesn't give me a status code like 404 or something (incidentally how do we attain the status code when using AFN 2.0?).
It should at least give an error. What does the failure handler print out?
So really my question is, why don't the parameters in the AFN 2.0 parameter property act in the same way as the parameters in the web app? And more generally why aren't the post request parameters working for me in AFN 2.0?
After examining how AFN (Version 2.0.1) encodes the parameters, it appears to me that these aren't encoded as they should: The application/x-www-form-urlencoded encoding algorithm.
Until this has been fixed, you may try the following workaround. The following algorithm encodes parameters strictly as suggested by w3c for HTTP 5, at least for Mac OS X 10.8 where I've tested it:
static NSString* form_urlencode_HTTP5_String(NSString* s) {
CFStringRef charactersToLeaveUnescaped = CFSTR(" ");
CFStringRef legalURLCharactersToBeEscaped = CFSTR("!$&'()+,/:;=?#~");
NSString *result = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(
kCFAllocatorDefault,
(__bridge CFStringRef)s,
charactersToLeaveUnescaped,
legalURLCharactersToBeEscaped,
kCFStringEncodingUTF8));
return [result stringByReplacingOccurrencesOfString:#" " withString:#"+"];
}
(Note: the code above depends on the implementation details of function CFURLCreateStringByAddingPercentEscapes. It's entirely possible to implement the suggested algorithm easily without any dependencies, which I would recommend - it becomes just not that short.)
static NSString* form_urlencode_HTTP5_Parameters(NSDictionary* parameters)
{
NSMutableString* result = [[NSMutableString alloc] init];
BOOL isFirst = YES;
for (NSString* name in parameters) {
if (!isFirst) {
[result appendString:#"&"];
}
isFirst = NO;
assert([name isKindOfClass:[NSString class]]);
NSString* value = parameters[name];
assert([value isKindOfClass:[NSString class]]);
NSString* encodedName = form_urlencode_HTTP5_String(name);
NSString* encodedValue = form_urlencode_HTTP5_String(value);
[result appendString:encodedName];
[result appendString:#"="];
[result appendString:encodedValue];
}
return [result copy];
}
Then, when using AFN, you can customize the serializing algorithm as shown below:
AFHTTPRequestOperationManager *operationManager = [AFHTTPRequestOperationManager manager];
operationManager.requestSerializer.queryStringSerializationWithBlock =
^NSString*(NSURLRequest *request,
NSDictionary *parameters,
NSError *__autoreleasing *error) {
NSString* encodedParams = form_urlencode_HTTP5_Parameters(parameters);
return encodedParams;
};
Put / after the url. I've missed it for hours.

iOS User Login Session via Devise but Auth_token not kept

I am building an iphone app with a rails-backed server. I am using the devise gem. I am having trouble with user logins on the client-side (everything works on the web side, and even in the terminal with CURL).
On Xcode I can create a user and I can login. After logging in
(and recieving this in the log: "User logged in!")
I am then pushed to the indexViewController- and here I receive an error that the posts don't load. The reason is because on the post_controller.rb I have a
before_filter :authenticate_user!
preventing the posts from loading. The problem is, that the auth_token which was generated upon a successful login, is not being stored and passed along to the different views. So then, in the log I get:
'You need to sign in before continuing.'
As if the first part of what I just explained never happened..
In the indexViewController viewDidLoad method I have:
if (![[APIClient sharedClient] isAuthorized]) {
LoginViewController *loginViewController = [[LoginViewController alloc] init];
[self.navigationController pushViewController:loginViewController animated:YES];
}
isAuthorized is a BOOL in the APIClient that checks if userID>0
In the user model this is the code that creates a login session
+ (void)loginUser:(NSString *)signature
email:(NSString *)email
password:(NSString *)password
block:(void (^)(User *user))block
{
NSDictionary *parameters = #{ #"user": #{
// #"signature": signature,
#"email": email,
#"password": password
}
};
[[APIClient sharedClient] postPath:#"/users/sign_in" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
User *user = [[User alloc] initWithDictionary:responseObject];
if (block) {
block(user);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
if (block) {
block(nil);
}
}];
}
I am guessing it is here that I am missing some auth_token implementation? Since it is generated automatically by devise- I am not sure how to tell xcode to remember it. The auth_token is a string that has a column in the user table on the db. Should I add auth_token as param to the dictionary that holds the user's email and username? Or how do I get the token to persist?
Any ideas would be helpful.
Not being intimately familiar with AFNetworking this is a stab in the dark, but presumably you need to set the token for subsequent requests. Assuming APIClient is a wrapper you've added around AFHTTPClient, here's a quick idea of what that might look like after reviewing the code here - AFHTTPClient.
+ (void)loginUser:(NSString *)signature
email:(NSString *)email
password:(NSString *)password
block:(void (^)(User *user))block {
NSDictionary *parameters = #{ #"user": #{ #"email": email,
#"password": password } };
[[APIClient sharedClient] postPath:#"/users/sign_in"
parameters:parameters
success:^(AFHTTPRequestOperation *operation, id responseObject) {
User *user = [[User alloc] initWithDictionary:responseObject];
// retrieve and save auth token
NSString *token = [responseObject objectForKey:#"authToken"];
[[APIClient sharedClient] setAuthorizationHeaderWithToken:token];
if (block) {
block(user);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
if (block) {
block(nil);
}
}];
}

XMPP authentication returns yes but XMPPStreamDidAuthenticate never called

I am trying to create an application that implements Facebook Chat. I have set up all of the XMPP stuff correctly to the best of my knowledge, but I cannot get it to work.
After the user has logged in and been authenticated to Facebook (via FBSession) I try to connect to the chat service. Here is where the XMPP comes in:
-(void)connect
{
[self setupStream];
NSError *err;
[self.xmppStream connectWithTimeout:10.00 error:&err];
}
-(void)setupStream
{
_xmppStream = [[XMPPStream alloc] initWithFacebookAppId:FACEBOOK_APP_ID];
[self.xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
}
- (void)xmppStreamDidConnect:(XMPPStream *)sender {
NSError *error;
NSError *err;
[self.xmppStream secureConnection:&err];
bool authed = [self.xmppStream authenticateWithFacebookAccessToken: FBSession.activeSession.accessTokenData.accessToken error:&error];
NSLog(#"%#", err);
NSLog(#"%#", [self.xmppStream authenticationDate]);
NSLog(#"%d, %#", authed, error);
}
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {
NSLog(#"did authenticate");
[self goOnline];
}
When running the above, everything seems to go fine: xmppStreamDidConnect is called after a short wait and authed always returns YES and its error is always null.
However, secureConnection returns Error Domain=XMPPStreamErrorDomain Code=1 "Please wait until the stream is connected." UserInfo=0xb23dc30 {NSLocalizedDescription=Please wait until the stream is connected.} The authenticationDate is always null as well. Also, none of the other delegate methods are ever called, including xmppStreamDidAuthenticate. What am I doing wrong?
I have finally found my answer!! Here it is, in case anyone else runs in to the same problem as me:
When calling openActiveSessionWithReadPermissions:allowLoginUI:completionHandler: the FBSession object does not actually communicate with the Facebook servers or attempt to authenticate with them, it simply loads the previous authenticationToken. In my case, this token had become invalid, but I did not realize it and nothing was there to tell me. I finally figured it out by logging the token and putting it in Facebook's Access Token Debugger. To check if your token is valid, you must call [FBSession renewSystemCredentials:] and await the result. Then you can determine if you need to manually closeAndClearTokenInformation before attempting to create a new token.

secure http calls in ios

How do I secure http call everytime I fire from my app and also it needs to have timeout so that any other user cannot use the same link from any browser.
I am looking for ios solution in particular and not html form.
Please help me out. Unable to resolve this issue and dont know in which direction to proceed.
Thanks in Advance.
I am attaching Working code for both PHP and ios which posts the Request and gets back the Response but no security is attached and any user can get the same Response by calling the same HTTP Response from Browser anytime...
ios code:
NSURL *url=[NSURL URLWithString:#"http://example.com/getmsgs/strno=123"];
NSURLRequest *request=[NSURLRequest requestWithURL:url];
connection=[NSURLConnection connectionWithRequest:request delegate:self];
if(connection){
webData=[[NSMutableData alloc]init];
}
NSError *requestError = NULL;
NSDictionary *allData=[NSJSONSerialization JSONObjectWithData:webdata options:0 error:&requestError];
if (requestError){
//An error occurred.
NSLog(#"error is : %#",requestError);
}
if (! allData) {
NSLog(#"Got an error: %#", requestError);
} else {
NSLog(#" data is : %#",allData) ;
}
NSArray *arrayOfEntry=[allData objectForKey:#"json"];
for (NSDictionary *diction in arrayOfEntry) {
NSString *label=[title objectForKey:#"image"];
NSString *label2=[title objectForKey:#"artist"];
NSString *label3=[title objectForKey:#"name"];
[array addObject:label];
[array addObject:label2];
[array addObject:label3];
}
php code:
<?php
$strno=$_GET['strno'];
if (isset($strno))
{
$connect=mysql_connect("localhost","test","test") or die ('Connection error!!!');
mysql_select_db("test") or die ('Database error!!!');
$query=mysql_query("select sno FROM users where strno='$strno';");
while($row = mysql_fetch_assoc($query))
{
$jsonoutput='{"json":{
"image":"'.$row['image'].'",
"artist":"'.$row['artist'].'",
"name":"'.$row['name'].'"
}}';
}
}
echo trim($jsonoutput);
mysql_close($connect) or die ('Unable to close connection-error!!!');
}
?>
You could use some kind of session to achieve what you want. For example, when user opens(runs) your ios app, you could connect to your web-service to get the session key (token), which would be unique for the device that app is running. And, when your ios app goes to the background, you could invalidate the token (using ios background execution would be appropriate here). Also, you could use time-limited session keys, meaning for example your session key will expire in 10 mins (which get invalidated on the server side), and for the new web requests your server has to issue another session key. Good Luck!

iOS 6 SDK SLRequest returning '400'

Let me make this clear. I am NOT using the Facebook SDK. I'm using iOS SDK's Social.framework, and ACAccountStore to access Facebook accounts, and post with it/them.
I use the same code to post on Twitter. It works 100%. But for some reason regardless of what I do for Facebook integration, I get a "400" error when I try to post.
My method is:
ACAccountStore *account = [[ACAccountStore alloc] init];
ACAccountType *facebookAccountType = [account accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
// Specify App ID and permissions
NSDictionary *options = #{ ACFacebookAppIdKey: #"MY_APP_ID",ACFacebookPermissionsKey: #[#"publish_stream", #"publish_actions"],ACFacebookAudienceKey: ACFacebookAudienceFriends };
[account requestAccessToAccountsWithType:facebookAccountType options:options
completion:^(BOOL granted, NSError *error)
{
if (granted == YES)
{
NSDictionary *parameters = #{#"message": string999};
NSURL *feedURL = [NSURL URLWithString:#"https://graph.facebook.com/me/feed"];
SLRequest *feedRequest = [SLRequest
requestForServiceType:SLServiceTypeFacebook
requestMethod:SLRequestMethodPOST
URL:feedURL
parameters:parameters];
acct.accountType = facebookAccountType;
// Post the request
[feedRequest setAccount:acct];
// Block handler to manage the response
[feedRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error)
{
if (granted && error == nil) {
} else {
NSLog(#"Facebook response, HTTP response: %i %#", [urlResponse statusCode], [error description]);
[self closeShareMenu];
}
}];
}
}
I don't know where I'm going wrong! It's so annoying! I've set up my app correctly in Facebook Developers and all! Please help -_-'
Following up to the chat session held between #fguchelaar and yours truly yesterday; I was able to ascertain the following solution for this issue.
Add the following in your iOS completion handler:
NSString *temp = [[NSString alloc] initWithData:data encoding: NSUTF8StringEncoding];
NSLog(temp);
//'data' is your 'responseData' (or another object name) that you declare in your completion handler.
This will allow you to see the exact cause of the issue printed to the Debug Console. Now depending on the issue presented, you'll need to grab a Facebook account from the Array of Accounts generated when you call this handler in the iPhone SDK. Not at any prior stage whatsoever, as the Access Token will likely expire and give you this '400' error.
In my case; the error printed was: error:{'400' A valid access token is required… which vastly annoyed me as my prior method to access and check the current Twitter account was working perfectly. And my theory was that it should work just as well for Facebook. Why should the access token be instantaneously revoked if I'm grabbing the account a split second before?
The way I solved my issue (depending on the reason for your error the answer can vary) was to use a for loop to check the newly created array of accounts, with the sole purpose of finding the account there with the same identifier string as the one I saved into NSData/NSKeyedArchiver.
for(ACAccount *a in arrayOfAccounts) {
if([a.identifier isEqualToString:storedAccount.identifier]) {
//set the account to be used
accountToBeUsed = a;
//don't forget to break the For loop once you have your result.
break;
} else {
//This else{} block is not strictly necessary, but here you could set an account if no account was found with a matching identifier.
}
}
For it to work, it's recommended to declare an ACAccount object in your View Controller's .h file, add a #property and #synthesize it, so it can be assigned within the for loop and used after the break; statement.
This effectively solved my whole issue with the '400' error. It was inexplicably frustrating for about six hours of my day, so I hope that my explanation helps anybody who happens to stumble across this issue, and my question here on Stack Overflow :)
Regards,
cocotutch