secure http calls in ios - iphone

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!

Related

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.

Can always login

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];
}

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

How to implement login functionality to native iphone app

I'm working on an app that asks the user to login to access some of his infrmations. I have a login.php file that is store on the server and all the usernames and passwords on the database.
On my app i have 2 uitextfields one for the username and one for the password. I understand that i can use the POST method to pass on the input to the web server and check wether the username and password match to then load the rest of the data. This is where am having trouble, can anyone help me with it, how do i pass on the inputs from the uitextfield to that web service to run the long.php script?
Skram's answer is correct, although you might be thinking what is ASIHTTPRequest?
You can get the framework here:
ASIHTTPrequest home
Here is a short beautiful tutorial on how to use it:
Awesome Tutorial
And here is some code I used to do a login some time ago:
-(IBAction)doLogin{
//make sure you have text in the username field, this is optional
if(![[username text] isEqualToString:#""]){
//URL of your web service
NSURL *url = [NSURL URLWithString:#"http://localhost:8888/myservice.php"];
//instantiate request object with URL
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
//Set post values before you send it off (forcing password to lowercase)
[request setPostValue:[[self.password text] lowercaseString] forKey:#"password"];
[request setPostValue:[username text] forKey:#"email"];
//this is optional, I have switch controlling what methods are called in the web service
[request setPostValue:#"2" forKey:#"method"];
//set the delegate to self for ASIHTTPRequest delegates (things you'll see in the tutorial)
[request setDelegate:self];
//send out request
[request startSynchronous];
//Now this code handles what happens after the web service call, notice I use a dictionary called user info to hold the response and I check the string to verify pass or fail and act accordingly.
NSString *verify = [NSString stringWithFormat:#"%#",[userinfo objectForKey:#"verify"]];
if([verify isEqualToString:#"pass"]){
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:
#"MainStoryboard_iPhone" bundle:[NSBundle mainBundle]];
UITabBarController *mainMenu =
[storyboard instantiateViewControllerWithIdentifier:#"mainMenu"];
[self.navigationController pushViewController:mainMenu animated:YES];
}
else{
//show login failed Dialog or something...
}
}}
Here some more code, this is what happens when the server returns a response.
- (void)requestFinished:(ASIHTTPRequest *)request{
if (request.responseStatusCode == 400) {
NSLog(#"Something is wrong");
} else if (request.responseStatusCode == 403) {
NSLog(#"Something is wrong");
} else if (request.responseStatusCode == 200) {
//the response code is good so proceed.
NSString *responseString = [request responseString];
userinfo = [responseString JSONValue];
NSLog(#"%#", [userinfo objectForKey:#"id"]);
NSLog(#"%#", [userinfo objectForKey:#"user"]);
NSLog(#"%#", [userinfo objectForKey:#"verify"]);
} else {
//print mystery code.
NSLog(#"%d",request.responseStatusCode);
}
}
Basically when you start the request using request startSynchronous it executes you server side code and returns a response string (or fails), you catch and handle the response string (or failure)in a delegate method you must implement from ASIHttpRequest -(void)requestFinished:(ASIHTTPRequest *)request. In the sample code I am parsing the response string into a JSON and then putting it into a dictionary for later use.
If you go through the tutorial this will all make sense to you very quickly. Hope it helps, good luck!
You would need to use a POST Request made to login.php Script on your server with a username and password value.
You can achieve this with NSURLConnection or a Framework such as ASIHTTPRequest's ASIFormDataRequest.
On your server you should do something like $_POST['username'] and $_POST['password'] to retrieve the values sent to your script to do the processing for your database.
EDIT: Basic example from iPhone Side with ASIHTTPRequest.
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:url]];
[request setPostValue:#"some_user" forKey:#"username"];
[request setPostValue:#"some_password" forKey:#"password"];
[request setDelegate:self];
[request startAsynchronous];
Implement the following method to catch the response:
-(void)requestFinished:(ASIHTTPRequest *)request {
NSLog(#"%#", [request responseString]);
}

Invalid Facebook access token

I am developing an application which posts videos to Facebook.
I have registered this app on Facebook, received APIkey, APIsecret, the app successfully passes authentication and receives the access token. Here is my code for authentication:
m_Facebook = [[Facebook alloc] init];
[m_Facebook logout:self];
m_FacebookUploader = [[FBVideoUpload alloc]init];
NSArray *permissions = [NSArray arrayWithObjects:#"publish_stream", #"offline_access",#"read_stream",nil];
m_Facebook.forceOldStyleAuth = YES;
[m_Facebook authorize:kApiKey permissions:permissions delegate:self];
However when trying to upload a video, the class FBVideoUpload tries to separate the access token into several parts:
- (NSString*) sessionID
{
NSArray *components = [accessToken componentsSeparatedByString:#"|"];
NSLog(#"components: %#", components);
return [components count] < 2 ? nil : [components objectAtIndex:1];
}
According to http://developers.facebook.com/docs/authentication/ the access token should contain several componenets, separated by "|", but the one I receive at authentication does not contain several components separated by a "|". The access_token I receive looks as follows:
AAA*GXJapke*BAGRlZC7aBLhiZB*MUEV*AAF6*ZBhZBw*0ER1M*vkXlRUZCwO*czfgs*wHbnA*BcTU*VrPZC*Yw3p*JmCIMZ*xSnCP*GqPRWZALgZDZ*
(I replaced some symbols with "*")
Here is my code for uploading the video:
[m_FacebookUploader setApiKey:kApiKey];
[m_FacebookUploader setAccessToken:m_Facebook.accessToken];
[m_FacebookUploader setAppSecret:kApiSecret];
[m_FacebookUploader startUploadWithURL:url params:params delegate:self];
I receive an error here:
if ([self sessionID] == nil) {
NSLog(#"Unable to retrieve session key from the access token.");
return;
}
Which not surprising since sessionID really returns nil.
Whatever library you're using to do that video upload is using some outdated logic to handle uploads. That whole method where it breaks apart the session key doesn't need to exist. Just use the access token you get back from FB with your video upload request. Also, be sure you're using our latest SDK https://github.com/facebook/facebook-ios-sdk