Trouble connecting iOS App with AWS EC2 server - swift

I am testing registration codes for an iOS app to a server hosted on AWS EC2 (tomcat, apache). I keep getting errors, like these:
TIC SSL Trust Error [1:0x283bc6280]: 3:0
NSURLSession/NSURLConnection HTTP load failed
(kCFStreamErrorDomainSSL, -9813)
Task <2F787366-D258-488D-AD2C-2FE696D08BF2>.<1> HTTP load failed
(error code: -1202 [3:-9813]).
I searched and changed the info.plist according to several suggestions:
// Here are my sample codes
// Send HTTP Request to Register user
let myUrl = URL(string: "https://ec2xxx.compute.amazonaws.com:8080/MyAPISever/api.json")
var request = URLRequest(url:myUrl!)
request.httpMethod = "POST"// Compose a query string
let postString = "username=\(userName)&password=\(userPassword)&first_name=\(firstName)&last_name=\(lastName)&email=\(userEmail)"
request.httpBody = postString.data(using: String.Encoding.utf8);
let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
// parse response....
task.resume()
Still the problem persists. I am using Swift 4.0 and Xcode 10.2. Here is my info.plist additions:
Allow Arbitary Loads
Exception Domains : amazonaws.com
IncludeSubdomains : true
NSExceptionAllowsInsecureHTTPLoads : true
NSExceptionRequiresForwardSecrecy : false
NSExceptionMinimumTLSVersion : TLSv1.2
NSRequiresCertificateTransparency : false

Related

Post Method Error : "The request timed out." - Swift

I am sending data to api using the post method. But while working in advance, I have now moved my server to the windows sdd server and started to get the problem I wrote below all the time. While working on Similator, it doesn't work when I try it on my physical phone, I get this problem. What is the problem? A situation related to the firewall? Because I started to get this problem after moving the server. Or another problem?
NSErrorFailingURLStringKey=....php, NSErrorFailingURLKey=....php,
_kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2102, NSLocalizedDescription=The request timed out.}
#objc func veriGonder() {
let url = NSURL(string: "...php")
var request = URLRequest(url: url! as URL)
request.httpMethod = "POST"
...
dataString = dataString + "&formCLASSNAMESTARIH\(verıTURUSTarih)"
dataString = dataString + "&formCLASSNAMESZAMAN\(verıTURUsZaman)"
...
let dataD = dataString.data(using: .utf8)
do {
let uploadJob = URLSession.shared.uploadTask(with: request, from: dataD)
{
data, response, error in
...
}
Here as the error specifies your request timed out. So to fix this either you need to increase the timeout interval or increase the server response interval from server-side. So, if it's the first option here's the code you need:
request.timeoutInterval = 100 // increase this to your desired value.

Attempts to access rapidAPI yahoo finance give me error 403 through swift

I am trying to use rapidAPI to access the Yahoo Finance API for a personal project. I registered for a free account and got an API key. Rapid API allows their users to copy and paste code to request data, so I took their demo code for accessing the API. Here it is for swift when trying to access details about a stock:
import Foundation
let headers = [
"x-rapidapi-host": "apidojo-yahoo-finance-v1.p.rapidapi.com",
"x-rapidapi-key": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" //private key
]
let request = NSMutableURLRequest(url: NSURL(string: "https://apidojo-yahoo-finance-
v1.p.rapidapi.com/stock/get-detail?region=US&lang=en&symbol=APPL")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
}
})
dataTask.resume()
When I run this code, it gives me error 403. This means that this data is forbidden according to their website. I have tried using other APIs and copying and pasting the demo code and they work fine. This API shouldn't be depreciated because it is running on the website demo. Here is the returning message I was given in Xcode:
I just checked Yahoo Finance API. The GET /get-detail endpoint seems to be deprecated now. Despite the fact that it's deprecated, it's still working for me.
Make sure to subscribe to this API. this could be the cause of the 403 code

Install TLS certificates on web server iOS app

I'm trying to integrate Swish payment in one of the apps I develop.
In order to be able to connect to the swish api I have to "set up TLS certificates from Swish Certificate Management and install it on "my" web server" according to the documentation.Here is the full technical documentation https://developer.getswish.se/merchants-api-manual/4-merchant-setup-process/.
The problem I don't understand is that I don't use a web server and I can't install those certificates there.
My app just offers some services for the client and after pressing the pay button should open the Swish app to finish the transaction in short.
What I tried is to make a post request to get the request token with which I can open the swish app loaded with the payment details.
I'm sure the problems are the certificates but couldn't find a good source explaining how to import(integrate) them.
let strURL = "https://mss.cpc.getswish.net/swish-cpcapi/api/v1/paymentrequests/"
guard let postURL = URL(string: strURL ) else {
print("Can't create url")
return
}
var request = URLRequest(url: postURL)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
let data: [String: Any] = [
"callbackUrl": "https://example.com/api/swishcb/paymentrequests",
"payeeAlias": "123xxxxxxx", // The Swish number of the payee. It needs to match with Merchant Swish number.
"amount": "100",
"currency": "SEK",
"message": "Test request to get the token"
]
do {
let jsonParams = try JSONSerialization.data(withJSONObject: data, options: [])
request.httpBody = jsonParams
} catch {
print("Error serializing the parameters of the post request")
return
}
// response will contain a Token, unique for each payment request
let config = URLSessionConfiguration.default
config.timeoutIntervalForResource = 120
config.timeoutIntervalForRequest = 120
let session = URLSession(configuration: config)
session.dataTask(with: request) { (data, response, error) in
print("Data \(data)")
print("Response \(response)")
if error != nil {
print("Error post request \(error?.localizedDescription)")
}
}.resume()
The error I got is:
Error post request Optional("An SSL error has occurred and a secure connection to the server cannot be made.")
018-12-21 12:24:55.549759+0200 tolk-24-7[7230:111102] [BoringSSL] boringssl_context_alert_callback_handler(3718) [C6.1:2][0x7fce4a77bf00] Alert level: fatal, description: handshake failure
2018-12-21 12:24:55.550047+0200 tolk-24-7[7230:111102] [BoringSSL] boringssl_session_errorlog(224) [C6.1:2][0x7fce4a77bf00] [boringssl_session_handshake_incomplete] SSL_ERROR_SSL(1): operation failed within the library
2018-12-21 12:24:55.550332+0200 tolk-24-7[7230:111102] [BoringSSL] boringssl_session_handshake_error_print(205) [C6.1:2][0x7fce4a77bf00] 140523985879704:error:10000410:SSL routines:OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURE:/BuildRoot/Library/Caches/com.apple.xbs/Sources/boringssl_Sim/boringssl-109.220.4/ssl/tls_record.cc:586:SSL alert number 40
2018-12-21 12:24:55.550585+0200 tolk-24-7[7230:111102] [BoringSSL] boringssl_context_get_error_code(3539) [C6.1:2][0x7fce4a77bf00] SSL_AD_HANDSHAKE_FAILURE
2018-12-21 12:24:55.552299+0200 tolk-24-7[7230:111102] TIC TCP Conn Failed [6:0x600002dd6c40]: 3:-9824 Err(-9824)
2018-12-21 12:24:55.555924+0200 tolk-24-7[7230:111102] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9824)
2018-12-21 12:24:55.556052+0200 tolk-24-7[7230:111102] Task <7888D080-D175-4DBF-8F66-4183F0D653E6>.<1> HTTP load failed (error code: -1200 [3:-9824])
2018-12-21 12:24:55.556234+0200 tolk-24-7[7230:111613] Task <7888D080-D175-4DBF-8F66-4183F0D653E6>.<1> finished with error - code: -1200
I feel your frustrations, I haven't worked with the Swish API per se, but it looks like URLSession is failing to perform the client certificate request. The handshake is failing on that step.
There is an option to add a URLSessionDelegate to URLSession in order to handle authentication challenges such as ServerTrust and ClientCertificate. They are discussing it here:
Swift 3 UrlSession with client authentication by certificate
If you're able to create a p12/pfx with the client certificate and private key, you can use SecPKCS12Import to import it and use it for the URLCredential trust in the NSURLAuthenticationMethodClientCertificate received in URLSessionDelegate. Here's an implementation I wrote:
func urlSession(
_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
{
let authenticationMethod = challenge.protectionSpace.authenticationMethod
if authenticationMethod == NSURLAuthenticationMethodServerTrust {
//Handle server trust if necessary
} else if authenticationMethod == NSURLAuthenticationMethodClientCertificate {
if let clientCredential = try? getClientUrlCredential() {
completionHandler(.useCredential, clientCredential)
} else {
completionHandler(.cancelAuthenticationChallenge, nil)
}
}
}
getClientUrlCredential function:
private func getClientUrlCredential() throws -> URLCredential {
let p12Data = getP12Data() //Get the data from the bundle if it's bundled in the app
let p12Key = getP12Key() //you need the key set for creating the p12/pfx
let certOptions: NSDictionary = [
kSecImportExportPassphrase as NSString : p12Key as NSString
]
// import certificate to read its entries
var items: CFArray?
let status = SecPKCS12Import(p12Data, certOptions, &items)
if status == errSecSuccess,
let items = items,
let dict = (items as Array).first as? [String: AnyObject],
let certChain = dict[kSecImportItemCertChain as String] as? [SecTrust] {
// Check if SecIdentityGetTypeID is present
guard let cfIdentity = dict[kSecImportItemIdentity as String] as CFTypeRef?,
CFGetTypeID(cfIdentity) == SecIdentityGetTypeID() else {
throw URLSessionPinningDelegateError.localClientCertificateError
}
let identity = dict[kSecImportItemIdentity as String] as! SecIdentity
return URLCredential(
identity: identity,
certificates: certChain,
persistence: .forSession
)
}
//Failed to read local certificate, throw error
throw URLSessionPinningDelegateError.localClientCertificateError
}
With a valid client certificate you should be able to fulfill the client hello and set up the TLS towards the server since this seems to be where you are failing right now. The SSL alert number 40 you're getting by BoringSSL suggests so to me at least.
Hope this points you in the right direction at least, happy to support further if needed.

NSURLConnection response returns 500 Status Code

I am trying to connect to a local node.js server setup and authenticate the user. I keep getting the 500 status code and can't figure out what I am missing.
I have tried hitting the server with these credentials from a web browser, and it works as expected.
Note: I do understand I have to use the NSURLSession instead of NSURLConnection, but for now, I need to get this to work.
Here is my code,
func signInUserWithDetails(userName:String,userPassword:String,serverURL:NSURL) {
let credDic :[String:String]=["user[name]":userName,
"user[password]":userPassword ]
self.httpMethod="PUT"
self.httpPath="/account"
self.expectedStatusCode=201
self.actualStatusCode=NSNotFound
self.requestUniqueIdentifier = NSUUID().UUIDString
let urlComponents = NSURLComponents(URL: serverURL, resolvingAgainstBaseURL: false)!
urlComponents.path = httpPath
let formedURL = urlComponents.URL!
var requestOrg = NSMutableURLRequest(URL: formedURL)
requestOrg.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
requestOrg.addValue("application/json", forHTTPHeaderField: "Accept")
requestOrg.HTTPMethod=self.httpMethod!
print(requestOrg.allHTTPHeaderFields) // Output 1
do{
let theJSONData = try NSJSONSerialization.dataWithJSONObject(credDic,options: NSJSONWritingOptions.PrettyPrinted)
let theJSONText = NSString(data: theJSONData,encoding: NSASCIIStringEncoding)
requestOrg.HTTPBody = theJSONData;
let tempD=try NSJSONSerialization.JSONObjectWithData(requestOrg.HTTPBody!, options: []) as? [String:String]
print("\(tempD)") //Output 2
}catch let error as NSError {
print(error)
}
connection = NSURLConnection(request: requestOrg, delegate: self, startImmediately: true)!
}
And I am just printing out the response with this,
func connection(didReceiveResponse: NSURLConnection, didReceiveResponse response: NSURLResponse) {
print("----------------------didReceiveResponse")
self.response=response
print("Response Received:"+"\(self.response)")
let urlResponse:NSHTTPURLResponse = response as! NSHTTPURLResponse
let responseCode=urlResponse.statusCode
self.actualStatusCode=responseCode
}
And the result I get is
Optional(["Accept": "application/json", "Content-Type": "application/x-www-form-urlencoded"])
Optional(["user[password]": "R", "user[name]": "R"])
----------------------didReceiveResponse
Response Received:Optional(<NSHTTPURLResponse: 0x7faba269d440> { URL: http://localhost:3000/account } { status code: 500, headers {
Connection = "keep-alive";
"Content-Length" = 1464;
"Content-Type" = "application/json";
Date = "Sat, 26 Dec 2015 08:34:45 GMT";
"X-Powered-By" = Express;
} })
And the didReceiveData throws this error
{"error":{"message":"Cannot read property 'name' of undefined","stack":"TypeError: Cannot read property 'name' of undefined\n at Object.exports.signIn [as handle] ( .......
Status code 500 means, that the server could not process your data and ran into an internal error. This oftentimes is caused by improperly encoded HTTP messages, where the server was unable to catch all possible errors.
When looking at your code, it becomes immediately apparent:
You are not sending a properly application/x-www-form-urlencoded encoded data to the server. This is likely the main cause of your problem. The other cause might be, that it's likely not a PUT but a POST method which is required to sign-in.
But before explaining how you encode your data properly, I would suggest to find out whether your server accepts JSON as content data (application/json). If so, properly encoding the data is much easier: having a JSON object (your variable credDic), simply convert it to JSON as UTF-8 in a NSData container. Then, get the length in bytes, set headers Content-Type and Content-Length accordingly.
I had a similar issue but after tried to include Content-Type using application/json, it was solved.
Example: request.addValue("application/json", forHTTPHeaderField: "Content-Type")
The client application gets an HTTP status code of 500 with the message "Internal Server Error" as a response for API calls. The 500 Internal Server error could be caused by an error during the execution of any policy within Edge or by an error on the target/backend server.
The HTTP status code 500 is a generic error response. It means that the server encountered an unexpected condition that prevented it from fulfilling the request. This error is usually returned by the server when no other error code is suitable

Swift NSURLSession HTTPS Self Sign - Request never reaches server

I'm having troubles performing a HTTPS post request to my django rest api. I have django-sslserver running to expose the api on port 8000. Things seem fine, when I make a request in a browser https://server-ip-addr:8000/api_view/ my browser complains "Hey! This guys certificate is self signed!" I say "yeah I know, that's me" and continue into the dangerous response.
Anyways I'm attempting to perform the same in Swift for an iOS application. I've found from this link here on implementing NSURLSession delegate protocols/functions NSURLSessionDelegate.URLSession() and NSURLSessionTaskDelegate.URLSession(). I've tweaked the example so that it atomically performs login attempts to my sslserver.
I've done so in the following code, a class implementing the two protocols above designed to pass username/password credentials to the server and wait for a response.
class SecureLogin: NSObject, NSURLSessionDelegate, NSURLSessionTaskDelegate {
func attemptLogin(username: String, password: String,
callback: ((NSData!,NSURLResponse!,NSError!) -> Void)?) {
println("inside attempt login")
var request = NSMutableURLRequest(URL: NSURL(string: "https://147.222.164.91:8000/ldapauth/")!)
request.HTTPMethod = "POST"
var params = ["username":username, "password":password] as Dictionary<String, String>
var err: NSError?
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options: nil, error: &err)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
var configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
var session = NSURLSession(configuration: configuration,
delegate: self,
delegateQueue:NSOperationQueue.mainQueue())
var task = session.dataTaskWithRequest(request,callback)
task.resume()
}
func URLSession(session: NSURLSession,
didReceiveChallenge challenge: NSURLAuthenticationChallenge,
completionHandler: (NSURLSessionAuthChallengeDisposition,NSURLCredential!) -> Void) {
println("Challenge received")
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust))
}
func URLSession(session: NSURLSession,
task: NSURLSessionTask,
willPerformHTTPRedirection response: NSHTTPURLResponse,
newRequest request: NSURLRequest,
completionHandler: (NSURLRequest!) -> Void) {
println("Redirection received")
var newRequest : NSURLRequest? = request
println(newRequest?.description)
completionHandler(newRequest)
}
}
So I go to attempt to perform the attemptLogin() function, providing the simple callback function to confirm a response
var gatekeeper = SecureLogin()
gatekeeper.attemptLogin(username, password: password, callback: {data, response, error -> Void in
println("inside gatekeeper")
}
println("beginning wait")
sleep(25)
I sleep the thread 25 seconds to keep the process alive long enough for the response to come in.
The output on the console looks like:
inside attempt login
beginning wait
Then the program dies, no response/"inside gatekeeper" message received, my django server terminal doesn't show any received requests either. I ran a sanity check: I've commented out the implementations of the delegate methods and the server receives the request, responds with:
inside attempt login
beginning wait
2015-01-27 11:29:37.192 LdapAuthSecure[12783:1475994] NSURLConnection/CFURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9812)
the expected error when there is no protocol for handling an authorization challenge.
Can anyone spot any problems with my implementation of the NSURLSession or its delegates? I find it very strange that the request doesn't even reach the server. Thank you for any help!
If this is iOS 9, and if you built your app against the iOS 9 (or later) SDK, you'll also have to tweak your Info.plist file to tell it to allow insecure loads. Otherwise, the URL loading system won't get as far as calling your authentication handler.
so I've never coded for iOS but I do know from memory that native apps will not popup a dialog nor accept self signed certificates by default.
If you own a domain (or if not, it's probably easier) you can get a free certificate from https://www.startssl.com/ or https://buy.wosign.com/free/
Or you can install the self signed certificate by emailing it to your phone and then opening it.
You can remove the self signed certificate from the profiles page in Settings.
I also found this answer for you: https://stackoverflow.com/a/22674004/4837003
But that looks like it will disable validation.