Soap request with NSData and base64 encoding - objective-c

I'm using a sudzc soap classes to communicate with a remote web service.
Most of requests works but i'm experiencing problem trasferring data:
i've to send some data encoded in base64, i allocate a NsData object this way:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"little_amount_of_data" ofType:#"dat"];
NSData* dummy = [NSData dataWithContentsOfFile:filePath];
[service sendAudioFile:self action:#selector(sendAudioFileHandler:) username: self.username password: self.password fileBytes: dummy numBytes: [dummy base64Encoding].length audioTimestamp: [NSString stringWithFormat:#"%0.f",[[NSDate date]timeIntervalSince1970]]];
The SOAP request looks right (data correctly encoded, right length) but i'm receiving this response from the server (iis7 i think, i don't have access to it):
Impossibile elaborare la richiesta. ---> Offset e lunghezza eccedono i limiti della matrice o il conteggio รจ maggiore del numero di elementi presenti dall'indice alla fine dell'insieme di origine.
translated:
Unable to process request. ---> Offset and length exceed the limits of the array or the count is greater than the number of items from the index at the end of the source.
if client sends a void base64 string (lenght=0), server replies with a success statement.
The WSDL describe the field as base64Binary
I'm using NSData+Base64.h/NSData+Base64.m
Any hints?
Is client or server fault?

solved, problem was on lenght. I was sending the lenght of the encoded file, the webservice wants the lenght of the original file.

Related

Send certificate in http request header - c++

I have a certificate that I need to send in the header of an http request. This is how I acquired the cert:
PCCERT_CONTEXT cert = nullptr;
wstring store = // store name
wstring subjectName = // subject name
HCERTSTORE hStoreHandle = CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0,
NULL,
CERT_SYSTEM_STORE_CURRENT_USER,
store.c_str());
cert = CertFindCertificateInStore(
hStoreHandle,
X509_ASN_ENCODING,
0,
CERT_FIND_SUBJECT_STR,
subjectName.c_str(),
NULL);
I need to send it as a custom header, as the load balancer that sits in front of my service strips off the certificate header ["X-ARR-CLIENTCERT"] before forwarding the request. I believe I need to send the cert->pbCertEncoded, but on the server, I can't decode it and convert it back to an X509Certificate2.
This is what I tried on the client:
request.headers().add("client-cert", cert->pbCertEncoded);
On the server:
var headerCert = Request.Headers["client-cert"];
byte[] certdata = Convert.FromBase64String(headerCert);
X509Certificate2 cert = new X509Certificate2(certdata);
The request header on the server is non-null. But it cannot parse it back to an X509Certificate2.
I tried another thing on the client. After getting the cert, I converted it to a string
DWORD size = 0;
CryptBinaryToString(cert->pbCertEncoded, cert->cbCertEncoded, CRYPT_STRING_BASE64, NULL, &size);
LPWSTR outstring = new TCHAR[size];
CryptBinaryToString(cert->pbCertEncoded, cert->cbCertEncoded, CRYPT_STRING_BASE64, outstring, &size);
If I try to send outstring in the header, it complains:
WinHttpAddRequestHeaders: 87: The parameter is incorrect.
But when I take the contents of outstring and try to parse it on the server, it decodes back to the right certificate. This tells me that I'm not doing something right when passing cert->pbCertEncoded in the header. Maybe I need to re-encode it or transform it somehow so the server can correctly parse it? I'd appreciate any help. Thanks!
My client is in c++ and server in .NET. I'm using cpprestsdk to send the certificate in the http request.
The pbCertEncoded is the ASN.1 encoded representation of the certificate. Look for instance here.
So you must encode the bytes to base64 for instance like this:
#include <Wincrypt.h>
#pragma comment (lib, "Crypt32.lib")
int ToBase64Crypto(const BYTE* pSrc, int nLenSrc, char* pDst, int nLenDst )
{
DWORD nLenOut = nLenDst;
BOOL fRet = CryptBinaryToString(
(const BYTE*)pSrc,
nLenSrc,
CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF,
pDst, &nLenOut
);
if (!fRet) {
nLenOut=0; // failed
}
return (nLenOut);
}

iOS keychain - Different values found on subsequent reads

I'm using the keychainItemWrapper to store a token in my ios keychain. I can write successfully and read the first time successfully. However, once I read subsequent times, or run my program again, I'm getting a different value, or data in a different format. Any ideas?
Details:
1) Using KeychainItemWrapper - https://gist.github.com/dhoerl/1170641
2) Testing on simulator
Code:
NSString* mytoken = #"eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIwYTVjM2U4N2FmY2I0NTNlYWEzZjI3MDBlYjgwZWE4YiIsInN1YiI6ImxpbmRzZXk0IiwiaWF0IjoxNTE5MTk5MTgxLCJuYmYiOjE1MTkxOTkxODEsImV4cCI6MTUxOTE5OTc4MX0.v10D61EE6tq6u9YG3QIQ_XefexlC22gwx-tv-HgOEsQ";
KeychainItemWrapper* keychain1 = [[KeychainItemWrapper alloc] initWithIdentifier:#"com.test.test" accessGroup:nil];
[keychain setObject:mytoken forKey:(id)kSecValueData];
NSString* result1a = [keychain1 objectForKey:(id)kSecValueData];
NSLog(#"result1a (works!):\n %#:", result1a);
result1a (works!):
eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIwYTVjM2U4N2FmY2I0NTNlYWEzZjI3MDBlYjgwZWE4YiIsInN1YiI6ImxpbmRzZXk0IiwiaWF0IjoxNTE5MTk5MTgxLCJuYmYiOjE1MTkxOTkxODEsImV4cCI6MTUxOTE5OTc4MX0.v10D61EE6tq6u9YG3QIQ_XefexlC22gwx-tv-HgOEsQ
NSString* result1b = [keychain1 objectForKey:(id)kSecValueData];
NSLog(#"result1b (works!):\n%#", result1b);
result1b (works!):
eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIwYTVjM2U4N2FmY2I0NTNlYWEzZjI3MDBlYjgwZWE4YiIsInN1YiI6ImxpbmRzZXk0IiwiaWF0IjoxNTE5MTk5MTgxLCJuYmYiOjE1MTkxOTkxODEsImV4cCI6MTUxOTE5OTc4MX0.v10D61EE6tq6u9YG3QIQ_XefexlC22gwx-tv-HgOEsQ
KeychainItemWrapper* keychain2 = [[KeychainItemWrapper alloc] initWithIdentifier:#"com.test.test" accessGroup:nil];
NSString* result2 = [keychain2 objectForKey:(id)kSecValueData];
NSLog(#"result2 (weird value!):\n%#", result2);
result2 (weird value!):
<65794a68 62476369 4f694a49 557a4931 4e694a39 2e65794a
7164476b 694f6949 77595456 6a4d3255 344e3246 6d593249 304e544e
6c595745 7a5a6a49 334d4442 6c596a67 775a5745 34596949 73496e4e
31596949 36496d78 70626d52 7a5a586b 30496977 69615746 30496a6f
784e5445 354d546b 354d5467 784c434a 75596d59 694f6a45 314d546b
784f546b 784f4445 73496d56 34634349 364d5455 784f5445 354f5463
344d5830 2e763130 44363145 45367471 36753959 47335149 515f5865
6665786c 43323267 77782d74 762d4867 4f457351>
You are actually getting the same value, but it's in hex format. If you convert that last value in to String you'll get the same value. You can see it on this hex converter http://string-functions.com/hex-string.aspx Just paste that last result and hit convert.
So for some reason, your first result is in String and your last result is in NSData format.

Why is my Destination IP Address seen as my Source IP Address when attempting to connect from a Handheld Device?

I am trying to call a REST method on a server from a handheld device with this code:
public static void WriteIt2( string fileName, string data )
{
// "filename" is what the file to save will be named; "data" is the contents of that file
if (File.Exists(fileName))
{
MessageBox.Show(String.Format("{0} exists - deleting", fileName));
File.Delete(fileName);
}
string justFileName = Path.GetFileNameWithoutExtension(fileName);
String uri = String.Format("http://192.168.125.50:21608/api/inventory/sendXML/duckbilled/platypus/{0}", justFileName);
SendXMLFile2(uri, data);
}
public static void SendXMLFile2(string uri, string data)
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
req.Method = "Post";
req.ContentType = "text/plain; charset=utf-8";
byte[] encodedBytes = Encoding.UTF8.GetBytes(data);
req.ContentLength = encodedBytes.Length;
Stream requestStream = req.GetRequestStream();
requestStream.Write(encodedBytes, 0, encodedBytes.Length);
requestStream.Close();
WebResponse result = req.GetResponse();
MessageBox.Show(result.ToString());
}
The breakpoint in my server code is not getting reached; I'm trying to find out why. I'm using RawCap and Wireshark to try to see exactly what's going on. After running RawCap and opening the .pcap file it creates in WireShark, and by then searching for any appearances of the port I'm trying to access (via Edit > Find Packet > Packet Bytes with "21608" as the search string") I found this in the Data for the only packet that contains that string:
SBCMYReportProviderStatusMessage#bgM
%<NetworkShield`http://192.168.125.50:21608/api/inventory/sendXML/duckbilled/platypus/INV_0000003.0916201413022
6z )
...so the code running on the handheld device is being picked up by WireShark, but Wireshark shows 192.168.125.50 as "Source" and 192.168.125.87 as "Destination" (Protocol == TCP, where I would kind of expect it to be HTTP).
192.168.125.50 is my PC's IP Address (should be the Destination, not the Source, right?)
192.168.125.87, the Destination, according to "nbtstat -a 192.168.125.87" is "BUCK, UNIQUE" I don't know or what "BUCK" is...(obviously, a computer on the local network)
The IP Address of the handheld is 192.168.55.101
Why does Wireshark not show 192.168.55.101 as the Source and 192.168.125.50 as the Destination? Is it possible to determine the reason for the failure (the REST method not getting hit) from this Wireshark data?
UPDATE
By right-clicking the Packet record in WireShark and selecting "Follow TCP Stream" I get the following:
SBCM.................w.......R.e.p.o.r.t.P.r.o.v.i.d.e.r.S.t.a.t.u.s.M.e.s.s.a.g.e.#...bg.M.....%.<....F.i.l.e.S.y.s.t.e.m.S.h.i.e.l.d.....l...C.:.\.W.i.n.d.o.w.s.\.a.s.s.e.m.b.l.y.\.N.a.t.i.v.e.I.m.a.g.e.s._.v.2...0...5.0.7.2.7._.3.2.. . . . [ much more of the same type of thing elided ]
.................SBCM.................Y.......R.e.p.o.r.t.P.r.o.v.i.d.e.r.S.t.a.t.u.s.M.e.s.s.a.g.e.#...bg.M.....%.<
...N.e.t.w.o.r.k.S.h.i.e.l.d.....`...h.t.t.p.:././.1.9.2...1.6.8...1.2.5...5.0.:.2.1.6.0.8./.a.p.i./.i.n.v.e.n.t.o.r.y./.s.e.n.d.X.M.L./.d.u.c.k.b.i.l.l.e.d./.p.l.a.t.y.p.u.s./.I.N.V._.0.0.0.0.0.0.3...0.9.1.6.2.0.1.4.1.3.0.2.2.6.....z ......)...SBCM.........................R.e.p.o.r.t.P.r.o.v.i.d.e.r.S.t.a.t.u.s.M.e.s.s.a.g.e.#...bg.M.....%.<....W.e.b.R.e.p........................JSBCM.........................R.e.p.o.r.t.M.a.i.n.S.t.a.t.u.s.M.e.s.s.a.g.e.#...bg.M.....%.<............................$.....O6.........R8e....E.......C.......C....B_.................SBCM.........................R.e.p.o.r.t.P.r.o.v.i.d.e.r.S.t.a.t.u.s.M.e.s.s.a.g.e.#...bg.M.....%.<....W.e.b.R.e.p........................JSBCM.........................R.e.p.o.r.t.M.a.i.n.S.t.a.t.u.s.M.e.s.s.a.g.e.#...bg.M.....%.<............................$.....O6.........R8e....E.......C.......C....B_.................
I cannot make heads or tails of this; I don't know what I should expect to see after my uri...I don't see any "ack" of either success or failure...

Downloaded PDF stored in Documents directory to be viewed in UIWebview but don't know how

The Problem: I try to load data to a webview but just get a black screen.
I have successfully downloaded a PDF and stored it in the documents directory but when I go to view it in a UIWebView I get nothing. I suspect this is because the data (as i have viewed it in the console) is hexadecimal and that the methods I am using to display it cannot read the data. Here is my code to load the data into a webview:
NSURL *url = [NSURL fileURLWithPath:PDFpathwithextension];
NSData *myData = [NSData dataWithContentsOfURL:url];
NSLog(#"data being loaded to webview =%#",myData);
[webview loadData:myData MIMEType:#"application/pdf" textEncodingName:#"utf-8" baseURL:nil];
Here's a sample of the data being printed from the NSlog:
"data being loaded to webview = b8e5f672 bec5562d 28b63505 9a2b7733 0595fb24 46eb982c d77a526e b02ecaf5 d69f227f 96e92b88 149118ca 09f33da2 677c8e7d 7707ebbf 889a73b5 e8776a00 86abd1ef 206d184f 0b9e8db5 0c381d2b a0b66e3d 543ba3c1 e64ca0ac ce34baac 2e9b6da9 2be01439 2c3c93c3 1e5050db 20ccabf5 88726af6 8ab36bfc 92aceae3 325df525 99b6fa27 c89f64da 2a22c9ac 22e24c3b 61747622 d2d99678 887d7713 57ce8ba8 75ba1eeb e044bf51 8739405a 907afc57 d31008f6 a697c1ea 0a817257 1494bae2 a8129786 36bb74ac 42571e3b bfa9889b db64e519 9aea02b2 1bdd425d e31e91b6 61589cde 3023496d 5890a634 dc976aea ff284971 12714a1d 6152eb88 28d5f182 07d877d7 3107f3a8 7d1cad80 bf09fba0 11a01d69 c06f7b0b fa1e370f 2cbb6450 dcfa2a98 3de150e8 89817ccf 762acf93 41e778f4 2c7d6b21 3babb58c 93d95ac3 cbd8d512 90bacb2b d4b88702 d5ee6966 bbfb3c93 e8becb24 b81f3189 2dff1125 361351a2 8b046e7f 46d31277 310797b1 0673a83f e546df8b 56a01b71 23b5b88e 97b60198 3a283076 3290dbb5 1c72bca1 a0f76e82 1dddf190 d5ada132 bb757486 d748a779 4bd81aaf 9da3f636 71b77775 f0555dfb 03e2ba26 05dbbace 0963bbee 08633bbf 16c6eefe b730b69d 0863db88 60abe705 37b1ff16 f0ceb31e 8071d4eb 4776234d ed00b60e d4ef0630 f402e8fa 0490b12f 08d2fb57 43aa2f1c 527c4ad0 f812413d 904e250d e8a9449f 8956f92a 58713e27 3bd6e7e1 287dfddc 2dbec3bc cdfd6779 51bedbbc a8feaf78 517ddff1 a37a093f 6a0fd2f3 82ab58f3 b378df63 5e80912e 803dc82e fc76a076 296ae7f5 03640e02 a80fd290 30c240fc c82b1077 2818b61d 52c0567f 2cc4fa93 20c6af85 e8d15cd8 325a426d 1aada636 8eeea415 fe5e56b8 7f8cb5c1 7f86b5de ff1e7bbd ffb7acb0 917fb1c3 0e124ed8 1072e005 1731e7b3 a87ba40f 7b11ed69 27d288df 953ecc01 6aef406b a4190588 9b00d83c c983c8a3 12501c5d 0e115321 103e1509 1ba6b7c2 6bd36a58 3fad83b0 37fec776 7940457d 6561fcfb 4f1f0670 e87d5004 2c048809 8385b180 0a28a271 5dd7e4e8 d1d5a0c6 8206bbb8 08414445 542c188a 4e5058aa 1d18d468 041d7b2c 472431ae 71755d13 7bd65812 ebdb8fe2 eeead9c3 f9f1a8ef 7bb7bcfb ee1d8940 f3780498 67a0a379 b1e467ce 91da9b8b 255ff33e c960fe51 326cfa5d 66281032 43be901b..."
Any reason you aren't using either the Quick Look Framework or UIDocumentInteractionController? They're able to provide the user with more functionality than a WebView and a little less cloogy.
Here are links to Apple's documentation:
https://developer.apple.com/library/ios/documentation/FileManagement/Conceptual/DocumentInteraction_TopicsForIOS/Articles/UsingtheQuickLookFramework.html
https://developer.apple.com/library/ios/documentation/uikit/reference/UIDocumentInteractionController_class/Reference/Reference.html
If you're looking to render the PDF from the app's filesystem, no need to fret! Just make sure that the pdf you have stored has a proper '.pdf' extension, then provide it to the QLPreviewController in full path:
self.contentURL = [NSURL fileURLWithPath:fullPath];
Is PDFpathwithextension a web url or local path ?
if web, first save myData to disk and try:
NSString *path = #"get full local path of your file including filename.extension";
NSURL *url = [NSURL fileURLWithPath:path];
[UIWebView alloc] loadRequest:[NSURLRequest requestWithURL:url]];
If you do not want to download it, then why use NSData?
Simply load pdf web url into a UIWebView.
[uiwebview loadrequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:PDFpathwithextension]]];

Cocoa: Handling 407 http response cfnetwork

I am creating downloader application.
I am facing a problem with proxy authentication.
I am getting 407 response code i.e proxy authentication required. I have valid proxy authentication details.
Following is Code Flow:
1. Create Http request using CFHTTPMessageCreateRequest
2. Set necessary header field values like Cache-Control, Accept-Ranges, Range & User-Agent using CFHTTPMessageSetHeaderFieldValue
3. Create read stream using CFReadStreamCreateForHTTPRequest
4. Set proxy server URL & port properties on read stream using CFReadStreamSetProperty
5. Set kCFStreamPropertyHTTPShouldAutoredirect to kCFBooleanTrue using CFReadStreamSetProperty
6. open read stream using CFReadStreamOpen
7. In a loop wait for stream to get opened
while (1)
{
if (kCFStreamStatusOpen == CFReadStreamGetStatus)
{
if (CFReadStreamHasBytesAvailable)
{
Get Http response header using CFReadStreamCopyProperty
Get response code using CFHTTPMessageGetResponseStatusCode
if (200 || 206 is response code)
SUCCESS
else check if response code is 407.
}
}
}
I tried using following code
if (407 == nsiStatusCode)
{
CFStreamError err;
cfAuthentication = CFHTTPAuthenticationCreateFromResponse(NULL, cfHttpResponse);
if ((cfAuthentication) && (CFHTTPAuthenticationIsValid(cfAuthentication, &err)))
{
if (CFHTTPAuthenticationRequiresUserNameAndPassword(cfAuthentication))
{
CFHTTPMessageApplyCredentials(cfHttpRequest, cfAuthentication, (CFStringRef)pnsUserName, (CFStringRef)pnsPassword, &err);
}
}
}
but unable to make it work.
How do I handle 407 status code so as to communicate with authenticating HTTP server?
Thanks in advance.
Vaibhav.
Build a CFHTTPMessageRef
-(CFHTTPMessageRef)buildMessage
{
NSURL *myURL = [NSURL URLWithString:#"http://myurl.com"];
NSData *dataToPost = [[NSString stringWithString:#"POST Data It Doesn't Matter What It Is"] dataUsingEncoding:NSUTF8StringEncoding];
//Create with the default allocator (NULL), a post request,
//the URL, and pick either
//kCFHTTPVersion1_0 or kCFHTTPVersion1_1
CFHTTPMessageRef request = CFHTTPMessageCreateRequest(NULL, CSTR("POST"), (CFURLRef)myURL, kCFHTTPVersion1_1);
CFHTTPMessageSetBody(request, (CFDataRef)dataToPost);
//Unfortunately, this isn't smart enough to set reasonable headers for you
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("HOST"), (CFStringRef)[myURL host]);
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Content-Length"), (CFStringRef)[NSString stringWithFormat:"%d", [dataToPost length]);
CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Content-Type"), CFSTR("charset=utf-8"));
return [NSMakeCollectable(request) autorelease];
}
Send it to the server and read back the response
-(CFHTTPMessageRef)performHTTPRequest:(CFHTTPMessageRef)request
{
CFReadStreamRef requestStream = CFReadStreamCreateForHTTPRequest(NULL, request);
CFReadStreamOpen(requestStream);
NSMutableData *responseBytes = [NSMutableData data];
CFIndex numBytesRead = 0 ;
do
{
UInt8 buf[1024];
numBytesRead = CFReadStreamRead(requestStream, buf, sizeof(buf));
if(numBytesRead > 0)
[responseBytes appendBytes:buf length:numBytesRead];
} while(numBytesRead > 0);
CFHTTPMessageRef response = (CFHTTPMessageRef)CFReadStreamCopyProperty(requestStream, kCFStreamPropertyHTTPResponseHeader);
CFHTTPMessageSetBody(response, (CFDataRef)responseBytes);
CFReadStreamClose(requestStream);
CFRelease(requestStream);
return [NSMakeCollectable(response) autorelease];
}
Adding Authentication to an HTTP Request
-(void)addAuthenticationToRequest:(CFHTTPMessageRef)request withResponse:(CFHTTPMessageRef)response
{
CFHTTPAuthenticationRef authentication = CFHTTPAuthenticationCreateFromResponse(NULL, response);
[NSMakeCollectable(authentication) autorelease];
CFStreamError err;
Boolean success = CFHTTPMessageApplyCredentials(request, authentication, CFSTR("username"), CFSTR("password"), &err);
}
Putting It All Together
-(void)magicHappens
{
CFHTTPMessageRef request = [self buildMessage];
CFHTTPMessageRef response = [self performHTTPRequest: request];
UInt32 statusCode;
statusCode = CFHTTPMessageGetResponseStatusCode(response);
//An HTTP status code of 401 or 407 indicates that authentication is
//required I use an auth count to make sure we don't get stuck in an
//infinite loop if our credentials are bad. Sometimes, making the
//request more than once lets it go through.
//I admit I don't know why.
int authCount = 0;
while((statusCode == 401 || statusCode == 407) && authCount < 3)
{
request = [self buildMessage];
[self addAuthenticationToRequest:request withResponse:response];
response = [self performHTTPRequest: request];
statusCode = CFHTTPMessageGetResponseStatusCode;
authCount++;
}
NSData *responseBodyData = [(NSData*)CFHTTPMessageCopyBody(response) autorelease];
NSString *responseBody = [[[NSString alloc] initWithData:responseBodyData encoding:NSUTF8StringEncoding] autorelease];
NSLog(responseBody);
}
Refer this link.