NSMutableUrlRequest not sending proper parameters for HTTP request - ios

I am trying to send a POST request so that a user can login to this app. However, when I try to send the information, the server returns an error message saying that it did not receive the login information. I have used this exact same code before but with the url having HTTPS instead of HTTP. Does swift 2 have a different method that deals with HTTP requests?
In my info.plist file I have added the following:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key><true/>
</dict>
The api calls work fine on every device except iOS, and the code works fine with a different url. If Swift 2 no longer accepts HTTP requests is there a work around?
static let URL = "http://url.com:3000"
static let netSession = NSURLSession.sharedSession() // A shared NSURLSession that will be used to make API calls
// Call to login with the provided credentials. If login is successful the handler function will
// receive 'true', otherwise 'false'.
static func login(email : String, password : String, handler : (success: Bool, error: APIError?) -> ()) {
let request = NSMutableURLRequest(URL: NSURL(string: "\(URL)/users/login")!)
request.HTTPMethod = "POST"
let params = ["email":email,"password":password]
request.HTTPBody = try? NSJSONSerialization.dataWithJSONObject(params, options: [])
netSession.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if error != nil {
handler(success: false, error: APIErrorNetwork)
return
}
let jsonResponse = JSON(data: data!)
let httpResponse = response as! NSHTTPURLResponse
if httpResponse.statusCode == 200 {
// Handle the expected response
} else {
handler(success: false, error: APIError(json: jsonResponse))
print(httpResponse.statusCode);
}
}).resume()
}

Are you sure your server accepts JSON? Does it expect you to post form data instead?
If it does expect JSON, try to add a Content-Type header to your request:
request.setValue("application/json", forHTTPHeaderField: "Accept");
Some servers are picky.

Related

Swift - HTTP digest auth

I am currently in the process of reverse engineering a home automation API. I want to manage all settings with my own app - because there is really no current home automation app of the company.
Anyway - I already managed the authentication with my SmartHome device. To not make it too complicated: I need http digest authentication for final communication.
I have already been able to connect to my device through the command line with curl - unfortunately this doesn't work in Swift as planned.
curl -X POST -d '{"key": "value"}' https://192.168.0.0:1/action -k -s --digest --user username:password
Translated to Swift:
(1) Using Alamofire
import Alamofire
let data: [String: any] = ["key": "value"]
let request = Alamofire.request("https://192.168.0.0:1/action", method: HTTPMethod.post, parameters: data);
request.authenticate(user: "username", password: "password")
request.responseJSON { response in
// leads to error because of invalid self signed certificate of the smart home device ("https:")
}
Note to Alamofire: I guess using an external libary such as AF does not make much sense in this case - there are some unresolved issues that wont let such code as above work. (Self signed ceritficates makes problems, using custom manager instances overriding internal stuff leads also to problems) - I've already spent hours believe me.
(2) Using not Alamofire :)
extension ViewController: URLSessionDelegate {
public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
let urlCredential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
completionHandler(.useCredential, urlCredential)
}
}
let session = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: nil)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
do {
let jsonData = try JSONSerialization.data(withJSONObject: data, options: .prettyPrinted)
request.httpBody = jsonData;
let task = session.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
return
}
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let responseJSON = responseJSON as? [String: Any] {
// success
}
}
task.resume()
} catch { }
The code above seems to work fine - the problem is that I've not implemented the digest authentication yet - because I do not find any method how to do this.
It would be super helpful if somebody to get some tips how generate the Auth header based on username and password
Edit
Curl uses this Authorization header:
> Digest username="username",
realm="XTV",
nonce="MTU5MDcNc2UxNjQ3OTo1YzMwYjc3YjIxMzAAAGQ5Nzg2NzUzMmRkZGU1ZVVlYw==",
uri="/action",
cnonce="MTExOTZlZmI1MjBlYWU0MTIzMDBmNDE0YTkWzJl1MDk=",
nc=00000001,
qop=auth,
response="2ba89269645e2aa24ac6f117d85e190c",
algorithm="MD5"
Is there the possibility to generate this header in Swift?
Digest authentication is supported automatically by URLSession and Alamofire through URLCredential (which is what authenticate() uses in Alamofire) when the server properly returns the WWW-Authenticate header with the proper digest settings.
You can generate the header manually, though I wouldn't recommend it due to the complexity of the digest process. I've found the wikipedia page to be thorough enough to implement the standard manually.

Getting error In posting Data in swift

I am sending the data using post method like this
let login = ["user_name":usernameTextField.text,"password":passwordTextField.text]
//["user":"ords_user#gmail.com", "pass":"ords_password"]
let url = NSURL(string: "http://localhost:8300")!
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: url)
do {
// JSON all the things
let auth = try NSJSONSerialization.dataWithJSONObject(login, options: .PrettyPrinted)
// Set the request content type to JSON
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
// The magic...set the HTTP request method to POST
request.HTTPMethod = "POST"
// Add the JSON serialized login data to the body
request.HTTPBody = auth
// Create the task that will send our login request (asynchronously)
let task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
// Do something with the HTTP response
print("Got response \(response) with error \(error)")
print("Done.")
})
// Start the task on a background thread
task.resume()
} catch {
// Handle your errors folks...
print("Error")
}
But I am getting the error message like
Argument type '[String : String?]' does not conform to expected type ‘AnyObject’
If I give the direct string it is accepting. If I am giving dynamically using the TextFields it is not coming. I don’t know what is the mistake I have done.
Can anyone Please help to solve this issue?
Thanks in advance.
I think your issue is that you are putting optional strings into the dictionary.
Try doing this:
guard
let username = usernameTextField.text,
let password = passwordTextField.text else {
return print("Need username & password")
}
let login = ["user_name": username,"password": password]
...
UITextField's text property returns an optional value, so compiler can't convert it to AnyObject.
You have to unwrap optionals before.
Try this
let login = ["user_name":usernameTextField.text,"password":passwordTextField.text] as Dictionary<String, AnyObject>

iOS9 + Swift: How To Set The Body of A Post Request Using a JSON Value?

I am trying to make an HTTP Post request to a development server with self signed certificate. This is the function making the POST call:
func makeHTTPPostRequest(path: String, body: JSON, onCompletion: (JSON?, NSError?) -> Void) {
let request = NSMutableURLRequest(URL: NSURL(string: path)!)
request.HTTPMethod = "POST"
// I am using SwiftyJSON
do {
request.HTTPBody = try body.rawData()
} catch _ { }
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue:NSOperationQueue.mainQueue())
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
var json: JSON?
if let _data = data {
json = JSON(data: _data)
}
onCompletion(json, error)
})
task.resume()
}
When I make a POST request, the server returns me "Empty fields" error even though I have properly set the HTTPBody of the request:
PS: The route is working fine when I call it from Postman.
The request.HTTPBody property must be a NSData object. If you want to send JSON, the data object should contain a sequence of Unicode characters (preferable UTF-8) which is your serialised JSON representation.
Additionally, you should also set the Content-Type header accordingly to application/json.

Can any one tell me why i am getting Bad authentication error while executing this code(Swift)?

I am using Fabric SDK to add the twitter login button in my app.......
i add the authentication header in my URL but still it is showing Bad authentication error while executing.
Suggest me how to add Header in the URL in Swift.
let twitter = Twitter.sharedInstance()
let oauthSigning = TWTROAuthSigning(authConfig:twitter.authConfig, authSession:twitter.session())
let authHeaders = oauthSigning.OAuthEchoHeadersToVerifyCredentials()
let request = NSMutableURLRequest(URL: NSURL(string: "https://api.twitter.com/1.1/search/tweets.json?q=Himan_dhawan")!)
request.allHTTPHeaderFields = authHeaders
println(request)
var session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
if((error) != nil) {
println(error.localizedDescription)
}
var strData = NSString(data: data, encoding: NSASCIIStringEncoding)
println(strData)
})
task.resume()
It's to do with the way that you're setting the headers on the request.
The Fabric doc's don't quite give you the full picture about creating the OAuth signing headers when wanting to use your own NSMutableURLRequest.
let authHeaders = oauthSigning.OAuthEchoHeadersToVerifyCredentials()
The return [NSObject : AnyObject]! dictionary gives you the values you need for the request. However, what it provides for the headers are different to what needs to be sent with the NSMutableURLRequest.
This is how you should be setting the headers for this request:
let twitter = Twitter.sharedInstance()
let oauthSigning = TWTROAuthSigning(authConfig:twitter.authConfig, authSession:twitter.session())
let authHeaders = oauthSigning.OAuthEchoHeadersToVerifyCredentials()
let mutableUrlWithUsableUrlAddress = NSMutableURLRequest(URL: usableUrlForRequest)
mutableUrlWithUsableUrlAddress.addValue(authHeaders[TWTROAuthEchoAuthorizationHeaderKey] as? String, forHTTPHeaderField: "Authorization")
This sets the required Authorisation Key as a value for the "Authorization" header on the request, opposed to when you pass in the authHeaders dictionary, it gets set for "X-Verify-Credentials-Authorization".
The Fabric doc's do go into this, but it's slightly more tucked away than it should be.

How to send json object in swift without "key - value" pair format

Hey so I have to send a a token string to the Django-server and it only accepts one string. I am trying to use alamo fire to do this, however I cant send a key-value pair to resolve this problem. Is there an alternative solution for this. I am new IOS developer and this is my first project and I am new to the community. Thank you.
Convert your dictionary into a JSON string and ship it off that way:
func jsonStringify(data: AnyObject) -> NSData? {
var error: NSError?
if let json = NSJSONSerialization.dataWithJSONObject(
data,
options: NSJSONWritingOptions(0),
error: &error
) {
return json
} else {
return nil
}
}
Depending on how you need to send the token (POST vs GET vs HTTP Body vs Query String)... you might need to change the below. But it should get you started with NSURLSession. This will send the token 189E23FL2 to the server with POST as a HTTP Body parameter.
let url = NSURL(string: "http://some-server/endpoint")
var request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "POST"
request.HTTPBody = "189E23FL2".dataUsingEncoding(NSUTF8StringEncoding)
// if you need a csrf token, add something like this as well:
// request.addValue("the-csrf-token", forHTTPHeaderField: "X-CSRFToken")
var sessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration()
var session = NSURLSession(configuration: sessionConfiguration)
var task = session.dataTaskWithRequest(request, completionHandler: { (data : NSData!, response : NSURLResponse!, error : NSError!) -> Void in
if (error == nil) {
println("Done!")
} else {
println("Errorororororor")
}
})
// start the task
task.resume()

Resources