I am using a web service with simple header authentication
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
NSString *userName = [_usernameTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];;
NSString *passWord = [_passwordTextfield.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
if ([challenge previousFailureCount] == 0) {
//Creating new credintial
NSURLCredential *newCredential = [NSURLCredential credentialWithUser:userName
password:passWord
persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
}
else {
CommonCode*objCommon=[[CommonCode alloc]init];
[_activityIndicator stopAnimating];
[objCommon showAlert:#"Invalid Password, or no user found with this Email Address"];
}
}
On the logout I am clearing the cokies with
- (void)resetCredintialCache {
NSDictionary *credentialsDict = [[NSURLCredentialStorage sharedCredentialStorage] allCredentials];
if ([credentialsDict count] > 0) {
// the credentialsDict has NSURLProtectionSpace objs as keys and dicts of userName => NSURLCredential
NSEnumerator *protectionSpaceEnumerator = [credentialsDict keyEnumerator];
id urlProtectionSpace;
// iterate over all NSURLProtectionSpaces
while (urlProtectionSpace = [protectionSpaceEnumerator nextObject]) {
NSEnumerator *userNameEnumerator = [credentialsDict[urlProtectionSpace] keyEnumerator];
id userName;
// iterate over all usernames for this protectionspace, which are the keys for the actual NSURLCredentials
while (userName = [userNameEnumerator nextObject]) {
NSURLCredential *cred = credentialsDict[urlProtectionSpace][userName];
[[NSURLCredentialStorage sharedCredentialStorage] removeCredential:cred forProtectionSpace:urlProtectionSpace];
}
}
NSURLCache *sharedCache = [NSURLCache sharedURLCache];
[sharedCache removeAllCachedResponses];
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray *cookies = [cookieStorage cookies];
for (NSHTTPCookie *cookie in cookies) {
[cookieStorage deleteCookie:cookie];
}
}
}
But after logout if I enter the wrong password I am logged in as theprevious user. How do I delete the cookies from the header of the HTTP request?
NSURLRequest has a cachePolicy property, which specifies the caching behaviour of the request.
Set the following cache policy NSURLRequestReloadIgnoringLocalCacheData when making the request like the example bellow will load the data from the url and not from the cache.
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10];
NSURLRequestReloadIgnoringLocalCacheData
Specifies that the data for the URL load should be loaded from the
originating source. No existing cache data should be used to satisfy a
URL load request.
https://developer.apple.com/library/prerelease/mac/documentation/Cocoa/Reference/Foundation/Classes/NSURLRequest_Class/index.html#//apple_ref/c/tdef/NSURLRequestCachePolicy
Related
I have a remote JavaScript file that I would like to load from WKWebView. The dev Website the JavaScript file is on requires Basic Auth in order to Access.
The JavaScript file needs needs to load as a result of a button.
In otherwords, I can't use the WKUserScript injectionTime options.
I have two code examples. Both of them only half work. I can't test if the auth works without the EvaluateJavascript working, and I can't test the EvaluateJavascript function without the Basic Auth working... so... using WKWebView * webView...
NSString *authStr = #"username:password";
NSData *authData = [authStr dataUsingEncoding:NSUTF8StringEncoding];
NSString *authValue = [NSString stringWithFormat: #"Basic %#",[authData base64EncodedStringWithOptions:0]];
NSURL* jsURL = [NSURL URLWithString:#"http://dev.xxxx.com/js/xxxxx.js"];
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:jsURL];
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
[_webView loadRequest:request];
I can see the javascript in the webView window, but it is not being evaluated.
Then I have this other strategy:
- (void)handleButton {
NSURL* jsURL = [NSURL URLWithString:#"http://dev.xxxx.com/js/xxxxx.js"];
_scriptString = [NSString stringWithContentsOfURL:jsURL usedEncoding:NSUTF8StringEncoding error:nil];
}
-(void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler{
if (challenge.previousFailureCount == 0){
NSURLCredentialPersistence persistence = NSURLCredentialPersistenceForSession;
NSURLCredential *credential = [NSURLCredential credentialWithUser:#"username" password:#"password" persistence:persistence];
completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
NSLog(#"in Auth");
}
else{
NSLog(#"%s: challenge.error = %#", __FUNCTION__, challenge.error);
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}
}
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
NSLog(#"navigation complete");
NSLog(#"scriptString %#", _scriptString); //Says UNAUTHORIZED
if ([_scriptString length] > 0) {
[_webView evaluateJavaScript:_scriptString completionHandler:^(NSString *result, NSError *evaluateError) {
if (result == nil) {
NSLog(#"no go dude: %#", evaluateError);
return;
}
NSData *data = [result dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"i think it worked: #%", data);
}];
}
}
Any help would be greatly appreciated!!
I loaded the javascript URL in Safari on my iPhone, and entered the basic auth username and password into the popup.
Then, this is the code that worked:
NSURL *jsURL = [NSURL URLWithString:#"http://username:password#dev.xxxx.com/js/xxxxxx.js"];
NSString *injectedJS = [NSString stringWithContentsOfURL:jsURL encoding:NSUTF8StringEncoding error:nil];
[_webView evaluateJavaScript:injectedJS completionHandler:nil];
I am trying to load a secure website in a UIWebView my basic approach is to create a NSURL, the n a NSURLRequest, then a NSURLConnection, then to load the NSURLRequest in the UIWebView. When the website is loaded I receive
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
I respond to the challenge sender with
- (void)useCredential:(NSURLCredential *)credential forAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
But after that I get nothing... it just hangs. I put in break points so I know that
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
is being called. If I wait till I am sure that the NSURLConnection is not going to complete then reload the view no authentication challenge is sent but the view will load. I do not have any control over the server. I am open to using AFNetworking, but only if necessary.
The full listing of source code is provided below:
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:
(NSURLAuthenticationChallenge *)challenge
{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
if ([challenge previousFailureCount] == 0)
{
NSString *username = #"username";
NSString *password = #"passsword";
NSURLCredential * cred = [NSURLCredential credentialWithUser:username
password:password
persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:cred forAuthenticationChallenge:challenge];
}
else
{
}
}
-(void)updateCard
{
NSURL * url = [NSURL URLWithString:#"https://ssl.letu.edu/applications/chapelattendance/attendance.html"];
NSURLRequest * request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:50.0];
self.webView =[[UIWebView alloc] initWithFrame:self.bounds];
self.webView.delegate = self;
[self.webView loadRequest:request];
self.connection = [[ NSURLConnection alloc]initWithRequest:request delegate:self];
[self.connection start];
}
Where did I go wrong?
You need to first retrieve the "authentication method" the server is requesting for:
[[challenge protectionSpace] authenticationMethod]
These are the authentication methods (which are string constants) which the expression above returns:
NSURLAuthenticationMethodDefault
NSURLAuthenticationMethodHTTPBasic
NSURLAuthenticationMethodHTTPDigest
NSURLAuthenticationMethodHTMLForm
NSURLAuthenticationMethodNegotiate
NSURLAuthenticationMethodNTLM
NSURLAuthenticationMethodClientCertificate
NSURLAuthenticationMethodServerTrust
Then, you have these options:
If you want to provide the credentials for the given authentication method, you invoke
useCredential:forAuthenticationChallenge:
If you don't want to handle that authentication method yourself and want the system try
to authenticate, you may invoke performDefaultHandlingForAuthenticationChallenge:
which may then fail or not, depending whether the system is capable to handle that type
of authentication and whether it can find credentials in well known storages.
If you cant handle that authentication method -- say authentication method
NSURLAuthenticationMethodNTLM for example -- you can skip this protection
space and try another protection space if another one
exists in this authentication challenge. Then you may possibly get an
authentication method NSURLAuthenticationMethodHTTPBasic which you
are capable to handle.
In order to reject the current protection space you send method
rejectProtectionSpaceAndContinueWithChallenge: to the
authentication challenge sender. Then, NSURLConnection will send
once again willSendRequestForAuthenticationChallenge: to your
delegate with another protection space if any further exists.
You may try to continue without providing credentials at all.
Likely, the authentication will fail. You can try it through
sending message continueWithoutCredentialForAuthenticationChallenge:
to the authentication challenge sender.
And finally, you can cancel the request through canceling the
authentication challenge: send cancelAuthenticationChallenge: to
the authentication challenge sender.
Note: NSURLAuthenticationMethodHTTPBasic and NSURLAuthenticationMethodHTTPDigest authentication methods can be handled with the same NSURLCredential object created with +credentialWithUser:password:persistence:
If anyone comes along and has the same problem be sure I want to share the solution I found. Use AFNetworking.
Here is the revised code:
-(void)updateCard
{
if(!self.webView)
{
self.webView =[[UIWebView alloc] initWithFrame:self.bounds];
self.webView.delegate = self;
}
NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults];
NSString *username = #"username";
NSString *password = #"password";
NSURL *url = [NSURL URLWithString:#"https://ssl.letu.edu/"];
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL: url];
[client setAuthorizationHeaderWithUsername:username password:password];
NSMutableURLRequest *request = [client requestWithMethod:#"GET" path:#"applications/chapelattendance/attendance.html"
parameters:nil];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
[self.webView loadRequest:request];
}
failure: ^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"Could not load chapel attendance");
}];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest];
operation.securityPolicy.allowInvalidCertificates = YES;
You need to send the username and password combination with the http header to authenticate the request while sending the same.
NSData *authData = [#"username:password" dataUsingEncoding:NSASCIIStringEncoding];
NSString *authorization = [NSString stringWithFormat:#"Basic %#", [authData base64Encoding]];
[mutableRequest addValue:authorization forHTTPHeaderField:#"Authorization"];
I am trying to access a specific URL that requires cookies through UIWebView but I can not access it because cookies are disabled. So I did the following:
Enabled cookies:
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
[cookieStorage setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
Created NSURLConnection and extracted cookies from response:
NSArray *cookies = [ NSHTTPCookie cookiesWithResponseHeaderFields: [ httpResponse allHeaderFields ] forURL:response.URL];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies: cookies forURL: response.URL mainDocumentURL:nil];
But neither of this didn't help. However if I launch the URL in safari it loads successfully and after that I can load the same URL in UIWebView too. Could you help me with this, how can I enable cookies for UIWebView?
Thanks in advance
After create a NSURLRequest, copy all cookies in sharedHTTPCookieStorage to NSURLRequest:
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPShouldHandleCookies:YES];
[self addCookies:cookies forRequest:request];
[_webView loadRequest:request];
And add addCookies:forRequest method
- (void)addCookies:(NSArray *)cookies forRequest:(NSMutableURLRequest *)request
{
if ([cookies count] > 0)
{
NSHTTPCookie *cookie;
NSString *cookieHeader = nil;
for (cookie in cookies)
{
if (!cookieHeader)
{
cookieHeader = [NSString stringWithFormat: #"%#=%#",[cookie name],[cookie value]];
}
else
{
cookieHeader = [NSString stringWithFormat: #"%#; %#=%#",cookieHeader,[cookie name],[cookie value]];
}
}
if (cookieHeader)
{
[request setValue:cookieHeader forHTTPHeaderField:#"Cookie"];
}
}
}
I would like to to get fetch JSON from http://mycompany.com/page1...http://mycompany.com/page2... On the the webserver side, it requires initial login http://mycompany.com/login, and after that a cookie is maintained for the user. How do I get this behavior with NSURLConnection without having to ask for login every time? Here is the non-working code using NSURLCredential Storage. Do I need to get the cookie from webservice at loging and then send it along with later requests? I struggled with this for some time, So can you please clarify your answer.
- (IBAction)getJSON:(id)sender
{
NSURLCredential *credential = [NSURLCredential credentialWithUser:#"user"
password:#"pass"
persistence:NSURLCredentialPersistenceForSession];
NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc]
initWithHost:#"myCompany.com"
port:0
protocol:#"http"
realm:nil
authenticationMethod:nil];
[[NSURLCredentialStorage sharedCredentialStorage] setDefaultCredential:credential
forProtectionSpace:protectionSpace];
//////////GET JSON//////////////
NSError *error;
NSURL *url = [NSURL URLWithString:#"http://mycompany.com.jsonpage1"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
//I am NOT getting JSON in this delegate
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"%#",responseString);
}
Reading cookies:
refer to Managing HTTP Cookies on iPhone
Setting cookie:
... set dictionary with cookie properties, then:
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:[NSDictionary dictionaryWithObjects:object forKeys:keys]];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
but keep in mind that session cookies can expire on your server
I need to invoke an initial GET HTTP request with Basic Authentication. This would be the first time the request is sent to the server and I already have the username & password so there's no need for a challenge from the server for authorization.
First question:
Does NSURLConnection have to be set as synchronous to do Basic Auth? According to the answer on this post, it seems that you can't do Basic Auth if you opt for the async route.
Anyone know of any some sample code that illustrates Basic Auth on a GET request without the need for a challenge response? Apple's documentation shows an example but only after the server has issued the challenge request to the client.
I'm kind of new the networking portion of the SDK and I'm not sure which of the other classes I should use to get this working. (I see the NSURLCredential class but it seems that it is used only with NSURLAuthenticationChallenge after the client has requested for an authorized resource from the server).
I'm using an asynchronous connection with MGTwitterEngine and it sets the authorization in the NSMutableURLRequest (theRequest) like so:
NSString *authStr = [NSString stringWithFormat:#"%#:%#", [self username], [self password]];
NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding];
NSString *authValue = [NSString stringWithFormat:#"Basic %#", [authData base64EncodingWithLineLength:80]];
[theRequest setValue:authValue forHTTPHeaderField:#"Authorization"];
I don't believe this method requires going through the challenge loop but I could be wrong
Even the question is answered, I want to present the solution, which doesn't require external libs, I found in another thread:
// Setup NSURLConnection
NSURL *URL = [NSURL URLWithString:url];
NSURLRequest *request = [NSURLRequest requestWithURL:URL
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:30.0];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
[connection release];
// NSURLConnection Delegates
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
if ([challenge previousFailureCount] == 0) {
NSLog(#"received authentication challenge");
NSURLCredential *newCredential = [NSURLCredential credentialWithUser:#"USER"
password:#"PASSWORD"
persistence:NSURLCredentialPersistenceForSession];
NSLog(#"credential created");
[[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
NSLog(#"responded to authentication challenge");
}
else {
NSLog(#"previous authentication failure");
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
...
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
...
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
...
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
...
}
Here is a detailed answer with no 3rd party involved:
Please check here:
//username and password value
NSString *username = #“your_username”;
NSString *password = #“your_password”;
//HTTP Basic Authentication
NSString *authenticationString = [NSString stringWithFormat:#"%#:%#", username, password]];
NSData *authenticationData = [authenticationString dataUsingEncoding:NSASCIIStringEncoding];
NSString *authenticationValue = [authenticationData base64Encoding];
//Set up your request
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://www.your-api.com/“]];
// Set your user login credentials
[request setValue:[NSString stringWithFormat:#"Basic %#", authenticationValue] forHTTPHeaderField:#"Authorization"];
// Send your request asynchronously
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *responseCode, NSData *responseData, NSError *responseError) {
if ([responseData length] > 0 && responseError == nil){
//logic here
}else if ([responseData length] == 0 && responseError == nil){
NSLog(#"data error: %#", responseError);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:#"Error accessing the data" delegate:nil cancelButtonTitle:#"Close" otherButtonTitles:nil];
[alert show];
[alert release];
}else if (responseError != nil && responseError.code == NSURLErrorTimedOut){
NSLog(#"data timeout: %#”, NSURLErrorTimedOut);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:#"connection timeout" delegate:nil cancelButtonTitle:#"Close" otherButtonTitles:nil];
[alert show];
[alert release];
}else if (responseError != nil){
NSLog(#"data download error: %#”,responseError);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:#"data download error" delegate:nil cancelButtonTitle:#"Close" otherButtonTitles:nil];
[alert show];
[alert release];
}
}]
Kindly let me know your feedback on this.
Thanks
If you don't want to import the whole of MGTwitterEngine and you aren't doing an asynchronous request
Then you can use
http://www.chrisumbel.com/article/basic_authentication_iphone_cocoa_touch
To base64 encode the Username and password
So replace
NSString *authValue = [NSString stringWithFormat:#"Basic %#", [authData base64EncodingWithLineLength:80]];
with
NSString *encodedLoginData = [Base64 encode:[loginString dataUsingEncoding:NSUTF8StringEncoding]];
after
you will need to include the following file
static char *alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
#implementation Base64
+(NSString *)encode:(NSData *)plainText {
int encodedLength = (((([plainText length] % 3) + [plainText length]) / 3) * 4) + 1;
unsigned char *outputBuffer = malloc(encodedLength);
unsigned char *inputBuffer = (unsigned char *)[plainText bytes];
NSInteger i;
NSInteger j = 0;
int remain;
for(i = 0; i < [plainText length]; i += 3) {
remain = [plainText length] - i;
outputBuffer[j++] = alphabet[(inputBuffer[i] & 0xFC) >> 2];
outputBuffer[j++] = alphabet[((inputBuffer[i] & 0x03) << 4) |
((remain > 1) ? ((inputBuffer[i + 1] & 0xF0) >> 4): 0)];
if(remain > 1)
outputBuffer[j++] = alphabet[((inputBuffer[i + 1] & 0x0F) << 2)
| ((remain > 2) ? ((inputBuffer[i + 2] & 0xC0) >> 6) : 0)];
else
outputBuffer[j++] = '=';
if(remain > 2)
outputBuffer[j++] = alphabet[inputBuffer[i + 2] & 0x3F];
else
outputBuffer[j++] = '=';
}
outputBuffer[j] = 0;
NSString *result = [NSString stringWithCString:outputBuffer length:strlen(outputBuffer)];
free(outputBuffer);
return result;
}
#end
Since NSData::dataUsingEncoding is deprecated (ios 7.0), you could use this solution:
// Forming string with credentials 'myusername:mypassword'
NSString *authStr = [NSString stringWithFormat:#"%#:%#", username, password];
// Getting data from it
NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding];
// Encoding data with base64 and converting back to NSString
NSString* authStrData = [[NSString alloc] initWithData:[authData base64EncodedDataWithOptions:NSDataBase64EncodingEndLineWithLineFeed] encoding:NSASCIIStringEncoding];
// Forming Basic Authorization string Header
NSString *authValue = [NSString stringWithFormat:#"Basic %#", authStrData];
// Assigning it to request
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
If you are using GTMHTTPFetcher for your connection, basic authentication is fairly easy as well. You simply need to provide the credential to the fetcher before beginning the fetch.
NSString * urlString = #"http://www.testurl.com/";
NSURL * url = [NSURL URLWithString:urlString];
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url];
NSURLCredential * credential = [NSURLCredential credentialWithUser:#"username" password:#"password" persistence:NSURLCredentialPersistenceForSession];
GTMHTTPFetcher * gFetcher = [GTMHTTPFetcher fetcherWithRequest:request];
gFetcher.credential = credential;
[gFetcher beginFetchWithDelegate:self didFinishSelector:#selector(fetchCompleted:withData:andError:)];
Can you tell me what's the reason behind limiting the encoding line length to 80 in your example code? I thought that HTTP headers have a max length of something like 4k (or maybe some servers don't take anything longer than that). – Justin Galzic Dec 29 '09 at 17:29
It is not limiting to 80, it is an option of the method base64EncodingWithLineLength in NSData+Base64.h/m, where you can split your encoded string into multiple lines, which is useful for other application, such as nntp transmission. I believe 80 is chosen by the twitter engine author to be a length big enough to accommodate most user/password encoded result to one line.
You can use AFNetworking (it is opensource), here is code that worked for me. This code sends file with basic authentication. Just change url, email and password.
NSString *serverUrl = [NSString stringWithFormat:#"http://www.yoursite.com/uploadlink", profile.host];
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] requestWithMethod:#"POST" URLString:serverUrl parameters:nil error:nil];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
// Forming string with credentials 'myusername:mypassword'
NSString *authStr = [NSString stringWithFormat:#"%#:%#", email, emailPassword];
// Getting data from it
NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding];
// Encoding data with base64 and converting back to NSString
NSString* authStrData = [[NSString alloc] initWithData:[authData base64EncodedDataWithOptions:NSDataBase64EncodingEndLineWithLineFeed] encoding:NSASCIIStringEncoding];
// Forming Basic Authorization string Header
NSString *authValue = [NSString stringWithFormat:#"Basic %#", authStrData];
// Assigning it to request
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
NSURL *filePath = [NSURL fileURLWithPath:[url path]];
NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithRequest:request fromFile:filePath progress:^(NSProgress * _Nonnull uploadProgress) {
// This is not called back on the main queue.
// You are responsible for dispatching to the main queue for UI updates
dispatch_async(dispatch_get_main_queue(), ^{
//Update the progress view
LLog(#"progres increase... %# , fraction: %f", uploadProgress.debugDescription, uploadProgress.fractionCompleted);
});
} completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
NSLog(#"Error: %#", error);
} else {
NSLog(#"Success: %# %#", response, responseObject);
}
}];
[uploadTask resume];