IOS - Handling Token Authentication in HTTP headers - ios

My organization has a number of different authentication methods used. One that I have been struggling with has been our apps that use Oath2 that will be expecting the Authorization header to have the token information to be stored in the HTTP Headers. I can manually put the Authorization header information for each request, but I would like this information to be automatically populated instead of manually adding it for every NSURLSession, NSURLConnection, UIWebView or [UIImage: imageFromUrl]. In Apples documentation for NSURLConnection class and NSURLSession it says that it will handle are designed to handle various aspects >of the HTTP protocol for you, including the Authentication header and they recommend not to alter this property, but it does not seem to get set for me. At a minimum I would expect that for the NSURLSession object I should only need to set it once by accessing the sharedSession and adding the header info via a setHTTPAdditionalHeaders call, but it does not seem to hold the info on the next time I access the sharedSession.
I there something I am missing here or do I need to manually populate the HTTP Header on all calls?
EDIT:
Below is a code snippet showing how I try to set the header for the session.
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
id jSONObj = [defaults objectForKey: kTokenInformation];
[config setHTTPAdditionalHeaders:#{#"Authorization": [NSString stringWithFormat:#"Bearer %#",[jSONObj valueForKeyPath:#"access_token"]]}];
session = [NSURLSession sessionWithConfiguration:config];
However, it doesn't appear that the token is present the next time I call [NSURLSession sharedSession]. So right now I have to do that every time I call the shared session. I also am unsure from the documentation how you would handle apps that maintain multiple sessions which may each require separate Auth tokens. Any thoughts what I am missing hear.

Have a look at NSURLSessionConfiguration.
For example, you could set up a singleton class that provides an NSURLSession:
// Session setup
NSString *tokenString = ...;
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
[sessionConfiguration setHTTPAdditionalHeaders:#{ #"X-Auth-Token" : tokenString" }];
self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
Now, every time you need to make a request you use your session:
// Send Request
NSURLSession *session = [[SessionManager sharedManager] session];
[[session dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
}] resume];
Here's a great tutorial: http://code.tutsplus.com/tutorials/networking-with-nsurlsession-part-1--mobile-21394

Related

Network calls take more time on iOS than on Android

I have a very strange problem, in Android, the API calls take 300-500 ms while in iOS it takes 1.5-2.5 sec. I have removed dependencies like my server, device specific issue, internet connectivity etc. I have a very simple sample code hitting a sample URL and for me, it takes about 2 sec, even on the simulator.
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(#"start");
// 1
NSURL *url = [NSURL URLWithString:#"https://httpbin.org/get"];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
// 2
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setValue:#"" forHTTPHeaderField:#"Accept-Encoding"];
request.HTTPMethod = #"GET";
[[session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// Handle response here
NSLog(#"end - %ld", (long)[(NSHTTPURLResponse*)response statusCode]);
}] resume];
});
I also have tried using AFNetworking and ASSIHTTP libraries, but there is no difference. I also have checked the headers and they are the same in both Android and iOS. What am I doing something wrong here?
I think your problem is not in the network but in this line:
dispatch_async(dispatch_get_global_queue(0, 0), ^{
Can you remove it and check again?
Data task is async so you don't need to wrap it in another async block.
Also you don't need to create instance of NSURLSession for every request
You can log out the timestamp (NSLog already did) when the request generate, send, callback to analyse it.
Does the server side code do any processing based on 'user-agent'?
Is there a time difference if you open the url in iOS safari and within the app ?
You can try calling the api from postman (or another REST API test tool like firefox RESTClient) and override the user-agent to use iOS values (http://www.enterpriseios.com/wiki/UserAgent). If the time difference is still the same, theres nothing you can do in your mobile code to fix this lag.
P.S. :
1. Overriding user-agent in postman needs some tweaking : https://github.com/postmanlabs/postman-app-support/wiki/Postman-Proxy

Cookies handling with JSONModel/JSONHTTPClient in iOS

In my current project I am using, +(void)postJSONFromURLWithString:(NSString*)urlString params:(NSDictionary*)params completion:(JSONObjectBlock)completeBlock; method to create account and log in my application for the very first time . For second time and onwards, log in call is not there, application directly opens the user's profile screen. But when I am updating user profile (name, contact number etc.), I am getting response status code 403 from by the statement
NSLog(#"Response status code = %i", (int)response.statusCode);
added in implementation of method
+(NSData*)syncRequestDataFromURL:(NSURL*)url method:(NSString*)method requestBody:(NSData*)bodyData headers:(NSDictionary*)headers etag:(NSString**)etag error:(JSONModelError**)err
403 is generally invoked due to authorization failure in server side.
Is there any way to see what are the cookies are going to server side while I am making an API call with
+(void)postJSONFromURLWithString:(NSString*)urlString params:(NSDictionary*)params completion:(JSONObjectBlock)completeBlock;?
JSONModel's built-in networking support is intentionally very basic/primitive/limited. It does not support custom authentication, cookies, etc.
You'd be best making a request with NSURLSession to get the data, then use JSONModel just for the deserialization - rather than for the whole request.
e.g.:
NSURLSession *session = [NSURLSession sharedSession];
NSURL *url = [NSURL URLWithString:#"https://example.com/mydata.json"];
NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
MyModel *obj = [[MyModel alloc] initWithData:data error:nil];
}];
[task resume];

How to encrypt data using public key under iOS

I'm pretty new with security topic and I have question about it. I create application under iOS. I need to connect with some server via HTTP and then get its public key (SSL certificate). Then I need to use this public key to encrypt some of data and send them to the same server. My problem is I have no idea how to do that. Can anyone explain to me how can I obtain the public key under iOS and then use it to encrypt data?
As an example, when you use a https-prefixed url (https==http over ssl), NSURLSession will handle this for you. A simple GET will look like the code below.All the handshake, public key stuff will be handled for you.
If you use post and send data to the server, the encryption will also be handled for you if a https url is used.
// use default session configuration
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
// create session without a delegate, use global operation queue
NSURLSession *session = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
// create a data task printing the response payload to NSLog
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:#"https://developer.apple.com"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Response: %#", responseString);
}];
// run
[dataTask resume];

Persistance of data in NSURLSession

I have a bunch of nested NSURLSessionDataTasks and the data downloaded persists on calls of the method. I think it might have something to do with how NSURLSession handles cache??
Is there some way I can flush the cache so I get the most recent data when I call the method (thats supposed to refresh the data)
Here's the code I'm working with if it helps at all...
--EDIT--
And a more readable excerpt of just one of the requests that I want to flush the cache from after use:
NSMutableURLRequest *homeRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"https://mistar.oakland.k12.mi.us/novi/StudentPortal/Home/Login"]]];
[homeRequest setCachePolicy:NSURLRequestReloadIgnoringCacheData];
[homeRequest setHTTPMethod:#"POST"];
NSString *postString = [NSString stringWithFormat:#"Pin=%#&Password=%#",
[self percentEscapeString:pin],
[self percentEscapeString:password]];
NSData * postBody = [postString dataUsingEncoding:NSUTF8StringEncoding];
[homeRequest setHTTPBody:postBody];
NSURLSessionDataTask *homeTask = [defaultSession dataTaskWithRequest:homeRequest
homeTask is the NSURLDataTask that I add to the defaultSession. I want to remove the cache it saves so that when I call the method that contains these lines again, it fetches from the server instead of the local cache.
Is defautSession a local variable pointing to [NSURLSession sharedSession]? I would try using an ephemeral session instead. It is almost the same except that it doesn't cache data to disk.
NSURLSessionConfiguration *config =
[NSURLSessionConfiguration ephemeralSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:config];
If that still doesn't fix the problem, then invalidate it before posting again. Use
[defaultSession invalidateAndCancel]
after your task has completed and then create a new session before the next time you need to post.

multiple download NSURLSession

I have a program that download a video from a url using NSURLSession, but i'm not able to do multiple download at the same time.
How can i do it?
How can i manage multiple simultaneous download?
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];
NSURLSessionDownloadTask *getVideo = [session downloadTaskWithURL:fileURL
completionHandler:^(NSURL *location,
NSURLResponse *response,
NSError *error) {
// 2
receivedData = [NSData dataWithContentsOfURL:location];
dispatch_async(dispatch_get_main_queue(), ^{
// do stuff with image
NSLog(#"%s receiveData:%d",__FUNCTION__,[receivedData length]);
});
}];
[getVideo resume];
From the code you have provided above you are not using any of the properties of NSURLSessionConfiguration class that would enable better download performance.
First of all I would look suggest using your own delegate queue. If you do not provide a queue then the session creates a serial operation queue for all delegate and completion handler calls see the "Creating a Session" section of the NSURLSession Class Reference document for more detail. You can look at the following properties of NSOperationQueue to help improve performance;
qualityOfService
maxConcurrentOperationCount
Next I would look at NSURLSessionConfiguration properties that may help.
HTTPMaximumConnectionsPerHost
HTTPShouldUsePipelining
Finally you should review the section "Life Cycle of a URL Session with Custom Delegates". You should confirm whether your using the delegate methods of NSURLSessionTaskDelegate and NSURLSessionDownloadTaskDelegate or just the completion handler.
You need to put more time into configuring NSURLSession to support the work you want to do.

Resources