ios sendAsynchronousRequest redirect basic auth - ios

Is it possible to use the sendAsynchronousRequest of NSURLConnection knowing the requested url will have a redirect and all request must also use basic auth?
I am getting the following error: Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn’t be completed. (NSURLErrorDomain error -1012.)
I did write some code using the NSURLConnectionDelegate and modified the redirect request to add the basic auth in the header and that worked.
So I'm guessing it has something to do with the authentication not being set on the second request. The same with the Delegate, If I didn't set the basic auth on the redirect request things were failing with a HTTP 401 unauthorized

It is possible I believe as I am doing it currently, here's my code, the trick is to set the header for "Authorization" with "Basic base64encodedmethod(username:password)"
//SETUP URL
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"https://YOURURLHERE"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:90.0];
//Get the username & password - then encode the values with Base64 (i googled for a library)
NSString *userAndPassword = [NSString stringWithFormat:#"%#:%#",userName,password];
NSString *encodedString = [userAndPassword base64EncodedString];
//Set the Authorization header which will now let your service calls pass basic authentication
[request addValue:[NSString stringWithFormat:#"Basic %#",encodedString] forHTTPHeaderField:#"Authorization"];
//Setup a queue and call the async request - remember to do items in your block on the
//main thread if it's for things like showing/hiding items as other threads will not run that code when you're expecting it
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
//your code block here
}];
I believe that answers your question, now I just need to find out how to delete that authentication so I can log the user out as I'm building this for a secure legal site. Any help there would be appreciated

Related

Invalid signed-request: Missing required parameter

I got the following response while getting my Photo from Instagram. Please help any help would be appreciated.
{
code = 403;
"error_message" = "Invalid signed-request: Missing required parameter 'sig'";
"error_type" = OAuthForbiddenException;
}
Here is my code
NSURL *url = [NSURL URLWithString:#"https://api.instagram.com/v1/tags/nofilter/media/recent?access_token=...........aef2"];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error){
}
else {
NSString * a = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSDictionary *tokenData = [jResponse objectWithString:a];
NSLog(#"%#",tokenData);
}
}];
Looks like you have enabled Enforce Signed Requests, so it requires you to have sig parameter which is signature for API request, described here: https://www.instagram.com/developer/secure-api-requests/
Either generate the signature or disable Enforce Signed Requests
Looks like you are making API call from an app (client side), so it is not recommended to make signed request, since u have to save the client_secret in the app code. It is recommended to do this on the server to be secure. So just disable the Enforce Signed Requests for you app and make API call as is.
A continution for #krisrak answer.
To disable Enforce Signed Requests.
Goto https://www.instagram.com/developer/clients/manage/
Select your Client required. Go to Security.Uncheck the Enforce signed requests
And save the updated changes.

How do I figure out when the contents of NSData indicate that a webservice request has failed?

I'm trying to persist data from a microsoft web service call to a file when my app starts up. If the app is able to complete the webservice request, it's storing the data in an NSData object. Assuming the data has been successfully requested and stored, I want to execute certain code that I would NOT want to if the webservice is unsuccessful.
My webservice request is as follows:
NSMutableURLRequest *request1 = [[NSMutableURLRequest alloc]init];
[request1 setURL:[NSURL URLWithString:#"---URL---"]];
[request1 setHTTPMethod:#"GET"];
NSURLResponse *request1Response;
NSData *request1Handler = [NSURLConnection sendSynchronousRequest:request1 returningResponse:&request1Response error:nil];
NSString *request1Reply = [[NSString alloc]initWithBytes:[request1Handler bytes] length:[request1Handler length] encoding:NSASCIIStringEncoding];
NSData *data1 = [request1Reply dataUsingEncoding:NSUTF16StringEncoding];
So basically, the response is dropped into that data1 object.
When connected to the internet, the request executes fine. The code that follows is wrapped in a if(data1){ conditional to make sure that the webservice request is successful before executing it. The problem is that when I disconnect from the internet(and cut off access to that webservice), the code inside the conditional is still being executed.
I tried comparing data1 to nil, logging data1 to do a direct comparison of the contents, etc, but I gather that that data1 object isn't nil; it probably contains some sort of failure message that I have thus far been unable to access. What can I do in the conditional or in the webservice request itself to figure out when the request fails?
Create an NSError object and pass it as argument to the sendSynchronousRequest: method, then if there is network or another error, the err object will populated with error information hence it will not be nil. That means you can check if(!err)contiune else there is an error
check the code:
NSMutableURLRequest *request1 = [[NSMutableURLRequest alloc]init];
[request1 setURL:[NSURL URLWithString:#"http://www.google.com"]];
[request1 setHTTPMethod:#"GET"];
//object where error will be saved
NSError *err;
NSURLResponse *request1Response;
NSData *request1Handler = [NSURLConnection sendSynchronousRequest:request1 returningResponse:&request1Response error:&err];//pass the err here by reference
NSString *request1Reply = [[NSString alloc]initWithBytes:[request1Handler bytes] length:[request1Handler length] encoding:NSASCIIStringEncoding];
NSData *data1 = [request1Reply dataUsingEncoding:NSUTF16StringEncoding];
and then you can check here:
if (err){
NSLog(#"error: %#", err);
}
You should at least be checking for an error response by populating the error pointer parameter.
Ideally you should be using a different API which gives you access to more details such as the response HTTP status code which you should be using to determine what happened even if you did get something which looks like success.

AFNetworking - add "image\jpeg" content type to AFImageResponseSerializer

I'm trying to load a picture from Facebook's source (a picture I've uploaded through my app and saved it's source).
I'm using AFNetworking to handle all my networking needs but when i'm trying to load a picture from:
http://fbcdn-sphotos-e-a.akamaihd.net/hphotos-ak-xfa1/v/t1.0-9/s720x720/10314676_10152739718934904_452946709678730535_n.jpg?oh=7e73d62e46c33e541e559e07e12bf275&oe=54B7E8CB&gda=1421866048_e364ab835ea15826e7ff28c8382ac085
(which opens in the browser, or in a regular http get request i'm setting in a http generator) but from the AFNetworking it always get a bad request (403) error..
I think that because the response from the server will be image\jpeg and i've ready that by default it doesn't work with AFNetworking..
How can i add it to the serialzer? or should i just write a new http request ?
imageView.imageResponseSerializer.acceptableContentTypes = [NSSet setWithObjects:#"image/jpeg", #"image/jpg"];
I've ended up using:
-(void) loadPictureFromUrl:(NSString*)urlString {
NSURL* url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if ( !error )
[_httpRequestDelegate httpResponseReceived:nil responsedData:[[UIImage alloc] initWithData:data]];
else
[_httpRequestDelegate httpRequestReturnedError:nil withError:error];
}];
}
instead of fighting with AfNetworking - which is usually awesome but has an issue with what i'm trying to do

Get an image from web with authentication

In my iOS app I need to load an image from web, but this image is on a server in which it's necessary to give username and password. I tried to use this code:
- (void) loadImageFromWeb:(NSString *)urlImg {
NSURL* url = [NSURL URLWithString:urlImg];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * data,
NSError * error) {
if (!error){
UIImage* image = [[UIImage alloc] initWithData:data];
[self.imageObjectScanned setImage:image];
} else {
NSLog(#"ERRORE: %#", error);
}
}];
}
But it return an error and says that:
Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn’t be completed. (NSURLErrorDomain error -1012.)" UserInfo=0x14e6b420 {NSErrorFailingURLKey=http://54.204.6.246/magento8/media/catalog/product/cache/0/image/9df78eab33525d08d6e5fb8d27136e95/s/c/scheda_non_shop.jpg, NSErrorFailingURLStringKey=http://54.204.6.246/magento8/media/catalog/product/cache/0/image/9df78eab33525d08d6e5fb8d27136e95/s/c/scheda_non_shop.jpg, NSUnderlyingError=0x14e695c0 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1012.)"}
I guess this error it's because I'm not sending the username and the password. How I can send username and password to load this image?
Try adding the basic authentication in header of your request object.
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
NSString *authCredentials = [NSString stringWithFormat:#"%#:%#", userName, password];
NSString *authValue = [NSString stringWithFormat:#"Basic %#",[authCredentials base64EncodedStringWithWrapWidth:0]];
[urlRequest setValue:authValue forHTTPHeaderField:#"Authorization"];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * data,
NSError * error) {
if (!error){
UIImage* image = [[UIImage alloc] initWithData:data];
[self.imageObjectScanned setImage:image];
} else {
NSLog(#"ERRORE: %#", error);
}
}];
Download the Base64.h/.m files from here and import it into your project.
Add header #import "Base64.h" in your implementation file.
This GitHub-issue suggests that your server is using an incorrect SSL certificate:
https://github.com/RestKit/RestKit/issues/1511
But if it is a credentials-issue, I suggest looking at NSURLCredential
https://developer.apple.com/library/mac/documentation/cocoa/reference/foundation/Classes/NSURLCredential_Class/Reference/Reference.html
You can present the credentials in a delegate method to NSURLConnection, or store them once and let them be used for all requests.
Alternatively, you could take a look into using RestKit.
You may try to pass the credentials within the URL as a query component, as described in the official documentation:
If authentication is required in order to download the request, the required credentials must be specified as part of the URL. If authentication fails, or credentials are missing, the connection will attempt to continue without credentials.
The parameters which comprises the query component need to be properly encoded. You may use this method to encode the parameters for a URL shown in this answer.
For example:
NSDictionary* parameters = #{#"login": name, #"password": password};
NSData* queryComponent = [parameters dataFormURLEncoded];
NSString* queryComponentString = [NSString alloc] initWithData:queryComponent
encoding:NSUTF8StringEncoding];
NSString* urlString = [NSString stringWithFormat:#"%#?%#",
urlImg, queryComponentString];
NSURL* url = [NSURL URLWithString: urlString];
A small caveat:
The described method which encodes the parameter included in the query component for a URL follows strictly the suggested algorithm specified by w3c: The application/x-www-form-urlencoded encoding algorithm which should be applied for URLs.
This encoding algorithm will escape a tilde character ~ when it occurs in either the name or value string. However, according the more general rules to compose a URL (see RFC 3986), the tilde character should not be escaped. I don't think this will ever be a problem, though.

AFNetworking HTTP request to Evernote API on iOS: error code 403

I am developing an iOS app that uses the Evernote API. Everything has been working fine, but then I started getting "code 403" to my requests.
Authentication to the service goes well: I am able log on and download all info I need (Notebooks, Notes, Note content, etc...). But when I try to get the thumbnails, I get 403.
My code for the request:
NSString *thumbnailPath = [NSString stringWithFormat:#"%#thm/note/%#?75", [[EvernoteSession sharedSession] webApiUrlPrefix], note.guid];
NSLog(#"THUMBNAILPATH %#", thumbnailPath);
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:[[EvernoteSession sharedSession] webApiUrlPrefix]]];
[httpClient clearAuthorizationHeader];
[httpClient setAuthorizationHeaderWithToken:[[EvernoteSession sharedSession] authenticationToken]];
[httpClient postPath:thumbnailPath parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
note.thumbnail = responseObject;
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"REQUEST: %#", thumbnailPath);
NSLog(#"Error: %#", error.localizedDescription);
}];
If I copy what the "REQUEST:" log result, it is a well-formatted link that gives me the thumbnail in my browser. But the second log gives me: "Error: Expected status code in (200-299), got 403".
I am out of ideas. Can anyone help?
You are not passing in the auth token correctly. This is how you would request a thumbnail for a note on iOS :
- (void)getThumbnailWithNoteGuid:(NSString*)noteGUID {
EvernoteSession* session = [EvernoteSession sharedSession];
NSString* fullTumbnailURL = [NSString stringWithFormat:#"%#thm/note/%#",[[EvernoteSession sharedSession]webApiUrlPrefix],noteGUID];
NSURL *url = [NSURL URLWithString:fullTumbnailURL];
NSMutableURLRequest* urlReq = [NSMutableURLRequest requestWithURL:url];
[urlReq setHTTPMethod:#"POST"];
[urlReq setHTTPBody:[[NSString stringWithFormat:#"auth=%#",[session.authenticationToken URLEncodedString]] dataUsingEncoding:NSUTF8StringEncoding]];
NSLog(#"full URL %#",fullTumbnailURL);
[NSURLConnection sendAsynchronousRequest:urlReq queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *urlREsp, NSData *respData, NSError *error) {
if(error == nil) {
NSLog(#"Thumbail data : %#",respData);
};
}];
}
403 - means forbidden. I haven't got expirience working with evernote but in based on other SDK's you're doing something wrong with request either you should go to evernote developers page. log in to your's account and look for some triggers. may be there some triggers which you should turn on to use this features
You should:
Make sure that you're hitting the fully constructed URL you intend to
Examine the entire returned body to see if there is additional error info provided
Examine full URL
Set a breakpoint in -[AFHTTPClient postPath:
parameters:
success:
failure:]. In the debugger, type po request to see the full URL that AFNetworking is hitting. Make sure that's what you want.
Examine entire body
In your failure block, you're only looking at the error object, created by AFNetworking to summarize the issue. However, the Evernote API could be providing additional info in the response body, which you can look at with NSLog(#"Response Body: %#", [operation responseString]).
Summary
Ultimately, your AFNetworking code is fine - this looks like an Evernote API issue. You're making the request wrong, your token is expired, or there's a bug on their end.
Side notes
It's inefficient to create a new AFHTTPClient instance for every request. You should probably use the singleton pattern to have one that sticks around for the lifetime of your app.
You should do some error checking before note.thumbnail = responseObject;. responseObject could be anything; make sure it's what you expect before you call your setter.

Resources