Till last night the code was working perfectly, but today i am facing a weird problem.
NSString *hostStr = [#"My API string" stringByAppendingString: #"/users/login"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:hostStr]];
[request setHTTPMethod:#"POST"];
NSString *boundary = #"-----FOO";
NSString *contentType = [NSString stringWithFormat:#"multipart/form-data; boundary=%#",boundary];
[request addValue:contentType forHTTPHeaderField:#"Content-Type"];
NSData *usernameData = [username dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:NO];
NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:NO];
NSMutableData *body = [NSMutableData data];
[body appendData:[[NSString stringWithFormat:#"\r\n--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[#"Content-Disposition: form-data; name=\"data[login_name]\"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[#"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[NSData dataWithData:usernameData]];
[body appendData:[[NSString stringWithFormat:#"\r\n--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[#"Content-Disposition: form-data; name=\"data[password]\"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[#"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[NSData dataWithData:passwordData]];
[body appendData:[[NSString stringWithFormat:#"\r\n--%#--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:body];
NSError *error;
NSURLResponse *response;
NSData *urlData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString *serverOutput = [[NSString alloc] initWithData:urlData encoding:NSUTF8StringEncoding];
NSLog(#"%#",serverOutput);
Above code gives me following response
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
<p>Additionally, a 404 Not Found
error was encountered while trying to use an ErrorDocument to handle the request.</p>
<hr>
<address>Apache Server at MY API URL Port 80</address>
</body></html>
But for the same lines of code when i comment this part
[body appendData:[[NSString stringWithFormat:#"\r\n--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[#"Content-Disposition: form-data; name=\"data[login_name]\"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[#"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[NSData dataWithData:usernameData]];
[body appendData:[[NSString stringWithFormat:#"\r\n--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[#"Content-Disposition: form-data; name=\"data[password]\"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[#"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[NSData dataWithData:passwordData]];
[body appendData:[[NSString stringWithFormat:#"\r\n--%#--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
It gives me following request response
{"login_name":"Username or Password is not valid","responseCode":"0"}
Means when i am not sending any data in HTTPBody, API call gives me desire response.
I have no any idea what is going wrong here. Many Thanks in advance.
Well. This is something that I never realized could be a problem.
As I more and more check my code, I found that there isn't any problem with my code up "there". But the problem was server side.
I contacted the server people and they said that they have enabled some ModSecurity so a multipart form data was not able to be sent in the HTTPBody.
This cost me two whole days to figure out. Hope it saves some one's time.
Related
I am trying to post to a web service using a multi-part form. However the service is saying it can't recognize the file upload I am trying to send. This is the section for the file upload.
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="GOO1242.pdf"
Content-Type: application/pdf
JVBERi0xLjQKJdP0zOE....... <rest of file>
----WebKitFormBoundary7MA4YWxkTrZu0gW
The error is
{
"type": "validation_error",
"detail": "There is no field: "file"."
}
Any ideas what is wrong?
Not sure if this is what you're looking for but I've used RestSharp to do this in a C# azure function
var apiRequest = await GetRestRequest(request);
var response = await SendRequest(apiRequest, log);
private async Task<RestRequest> GetRestRequest(string requestInput)
{
var uploadRequestInput = JsonConvert.DeserializeObject<UploadModelRequest>(requestInput);
var base64EncodedBytes = Convert.FromBase64String(uploadRequestInput.Content);
var uploadBicxRequest = JsonConvert.DeserializeObject<UploadModelRequest>(requestBody);
var apiRequest = new RestRequest("system/archive/document", Method.POST);
apiRequest.AddParameter("key", JsonConvert.SerializeObject(uploadRequest), "application/json", ParameterType.RequestBody);
apiRequest.AddFileBytes("VersionData", base64EncodedBytes, uploadRequest.PathOnClient, "application/octet-stream");
apiRequest.AddHeader("Content-Type", "multipart/form-data");
return apiRequest;
}
Below is the code snippet to consume an api endpoint. For 200 http response, the exchange object contains the payload received. But for 400 response, the payload received is not set in exchange object. Is anything missing in the code below?
Exchange exchange = serviceProducer.send(endPoint, new Processor() {
public void process(Exchange exchange) throws Exception {
exchange.setPattern(ExchangePattern.InOut);
Message inMessage = exchange.getIn();
inMessage.setHeader(CxfConstants.CAMEL_CXF_RS_USING_HTTP_API, Boolean.TRUE);
inMessage.setHeader(Exchange.CONTENT_TYPE, "application/json");
inMessage.setHeader(Exchange.HTTP_METHOD, "POST");
inMessage.setHeader(Exchange.HTTP_QUERY, "clientId=" + ClientId);
inMessage.setBody(request);
inMessage.setHeader(CxfConstants.CAMEL_CXF_RS_RESPONSE_CLASS, SearchResponse.class);
inMessage.setHeader(Exchange.CONTENT_TYPE, "application/json");
}
});
SearchResponse searchResponse = (SearchResponse) exchange.getOut().getBody();
getOut() creates a blank output message. You need to use getIn() or getMessage().
SearchResponse searchResponse = (SearchResponse) exchange.getIn().getBody();
https://camel.apache.org/manual/latest/faq/using-getin-or-getout-methods-on-exchange.html#UsinggetInorgetOutmethodsonExchange-UsinggetInorgetOutmethodsonExchange
I am new in react native and wanted to consume soap service but did not get any api to do that. I have used fetch api for Rest service with json parser. Is there any api available to consume soap service and parse xml in react-native. In ios we create soap envelope and send to the server like :
NSString *soapMessage = [NSString stringWithFormat:
#"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchem\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
"<soap:Body>\n"
"<GetCitiesByCountry xmlns=\"http://www.webserviceX.NET\">\n"
"<CountryName>%#</CountryName>\n"
"</GetCitiesByCountry>\n"
"</soap:Body>\n"
"</soap:Envelope>\n",#"India"];
NSURL *url = [NSURL URLWithString:#"http://webservicex.com/globalweather.asmx"];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
[theRequest addValue: #"http://www.webserviceX.NET/GetCitiesByCountry"
forHTTPHeaderField:#"SOAPAction"];
[theRequest addValue: [NSString stringWithFormat:#"%lu",(unsigned long)[soapMessage length]]
forHTTPHeaderField:#"Content-Length"];
[theRequest setHTTPMethod:#"POST"];
[theRequest addValue: #"text/xml; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[theRequest setHTTPBody: [soapMessage dataUsingEncoding:NSUTF8StringEncoding]];
self.responseData = [[NSMutableData alloc]init];
NSURLSession *soapSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionDataTask *dataTask = [soapSession dataTaskWithRequest:theRequest];
[dataTask resume];
Same thing I am looking in react-native.
I have a HTTP POST servlet to receive SAML response and decode the response, then get the email from response. Suppose my IDP endpoint is https://myIdp.com. Following is an response example:
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_8e8dc5f69a98cc4c1ff3427e5ce34606fd672f91e6" Version="2.0" IssueInstant="2014-07-17T01:01:48Z" Destination="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685">
<saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="pfx0e02f9bf-9d08-14ab-b927-4ab9b979e46b" Version="2.0" IssueInstant="2014-07-17T01:01:48Z">
<saml:Issuer>http://idp.example.com/metadata.php</saml:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#pfx0e02f9bf-9d08-14ab-b927-4ab9b979e46b"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>ckLpItzLtCvyEpzIMpBoOB4HQdU=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>VPa3SbxN6EzHKb3qg4Q8nh3eGok9rwifeZ3QPn784zOEqxxJcqttI8unOHiQJRjf5fepBvuWegPqAWSWi3vlAlSyHfVdofF1hthJJdDY94mT9jIc9rMKhm1zpn5b1LE3Pl6Bg0AMUlN7ajZP5v3lLSJPuGEAaptdQFHc1j5m0sU=</ds:SignatureValue>
<ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIICajCCAdOgAwIBAgIBADANBgkqhkiG9w0BAQ0FADBSMQswCQYDVQQGEwJ1czETMBEGA1UECAwKQ2FsaWZvcm5pYTEVMBMGA1UECgwMT25lbG9naW4gSW5jMRcwFQYDVQQDDA5zcC5leGFtcGxlLmNvbTAeFw0xNDA3MTcxNDEyNTZaFw0xNTA3MTcxNDEyNTZaMFIxCzAJBgNVBAYTAnVzMRMwEQYDVQQIDApDYWxpZm9ybmlhMRUwEwYDVQQKDAxPbmVsb2dpbiBJbmMxFzAVBgNVBAMMDnNwLmV4YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZx+ON4IUoIWxgukTb1tOiX3bMYzYQiwWPUNMp+Fq82xoNogso2bykZG0yiJm5o8zv/sd6pGouayMgkx/2FSOdc36T0jGbCHuRSbtia0PEzNIRtmViMrt3AeoWBidRXmZsxCNLwgIV6dn2WpuE5Az0bHgpZnQxTKFek0BMKU/d8wIDAQABo1AwTjAdBgNVHQ4EFgQUGHxYqZYyX7cTxKVODVgZwSTdCnwwHwYDVR0jBBgwFoAUGHxYqZYyX7cTxKVODVgZwSTdCnwwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQ0FAAOBgQByFOl+hMFICbd3DJfnp2Rgd/dqttsZG/tyhILWvErbio/DEe98mXpowhTkC04ENprOyXi7ZbUqiicF89uAGyt1oqgTUCD1VsLahqIcmrzgumNyTwLGWo17WDAa1/usDhetWAMhgzF/Cnf5ek0nK00m0YZGyc4LzgD0CROMASTWNg==</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature>
<saml:Subject>
<saml:NameID SPNameQualifier="http://sp.example.com/demo1/metadata.php" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData NotOnOrAfter="2024-01-18T06:21:48Z" Recipient="http://sp.example.com/demo1/index.php?acs" InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2014-07-17T01:01:18Z" NotOnOrAfter="2024-01-18T06:21:48Z">
<saml:AudienceRestriction>
<saml:Audience>http://sp.example.com/demo1/metadata.php</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement AuthnInstant="2014-07-17T01:01:48Z" SessionNotOnOrAfter="2024-07-17T09:01:48Z" SessionIndex="_be9967abd904ddcae3c0eb4189adbe3f71e327cf93">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<saml:AttributeStatement>
<saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue xsi:type="xs:string">test</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue xsi:type="xs:string">kliu#myIdp.com</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</samlp:Response>
If someone knows the format of the response, he can use some post tools such as PostMan to send a post request to my SP post servlet. For example, he replaces the following attribute:
<saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue xsi:type="xs:string">kliu.fake#myIdp.com</saml:AttributeValue>
</saml:Attribute>
This request is not from myIdp.com. But my servlet could not validate if it is from myIdp.com. Is there a way to deny the fake request?
There is and I can get the signature using OpenSAML. I found some people using following code, but how to get the publicKey then get the publicCredential?
try {
BasicX509Credential publicCredential = new BasicX509Credential();
publicCredential.setPublicKey(publicKey);
SignatureValidator signatureValidator = new SignatureValidator(publicCredential);
signatureValidator.validate(signature);
} catch (ValidationException e) {
e.printStackTrace();
// throw new InvalidAssertionException("Assertion signature validation failed.");
}
I am using IDOL API to convert a pdf file to html in Salesforce Apex class.
When I am using simple html, like:
<html>
<body>
<form action="https://api.idolondemand.com/1/api/sync/viewdocument/v1"
method="Post" enctype="multipart/form-data">
<input type="hidden" name="raw_html" value="true"/>
<input type="hidden" name="apikey"
value="{apikey removed}"/>
<input type='FILE' name='file'/><br/>
<input type='submit' name='upload_btn' value='Submit'/>
</form>
</body>
</html>
then this is working. But when I am using APEX code httprequest, then this is making a bad request.
My APEX code is:
public HTTPResponse uploadFile(Attachment file){
//String boundary = '---------------------\n';
String header = '\n';
header += 'Content-Disposition: form-data; name="file"; filename="'
+ file.Name +'"\nContent-Type: application/pdf\n\n';
String footer = '\n';
String querybody = '\n Content-Disposition: form-data;
name="raw_html"\n\n'+true+'\n';
querybody = querybody + '\n Content-Disposition: form-data;
name="apikey"\n\n {apikey removed} \n\n';
//base64 encoded body
String bodyEncoded = EncodingUtil.base64Encode(file.body);
//last encoded body bytes
String last4Bytes =
bodyEncoded.substring(bodyEncoded.length()-4,bodyEncoded.length());
//if the last 4 bytes encoded base64 ends with the padding character (=
or ==) then re-encode those bytes with the footer
//to ensure the padding is added only at the end of the body
if(last4Bytes.endsWith('='))
{
Blob decoded4Bytes = EncodingUtil.base64Decode(last4Bytes);
HttpRequest tmp = new HttpRequest();
tmp.setBodyAsBlob(decoded4Bytes);
String last4BytesFooter = tmp.getBody()+footer;
bodyEncoded = querybody + header +
bodyEncoded.substring(0,bodyEncoded.length()-4) +
EncodingUtil.base64Encode(Blob.valueOf(last4BytesFooter)) +
footer;
}
else
{
bodyEncoded = querybody + header + bodyEncoded + footer;
}
bodyEncoded = querybody;// + header + bodyEncoded + footer;
System.debug('>>>>>>>>>>>>>>>>>>>>>>' + bodyEncoded);
HttpRequest req = new HttpRequest();
req.setHeader('Content-Type','multipart/mixed');
req.setMethod('POST');
req.setEndpoint('https://api.idolondemand.com/1/api/sync/viewdocument/v1'
);
req.setBody(bodyEncoded);
req.setTimeout(120000);
req.setHeader('Content-Length', String.valueof(req.getBody().length()));
Http http = new Http();
Httpresponse res = http.send(req);
return res;
}
My Visual force page containing only:
<apex:page controller="IDOLService">
<apex:form >
<apex:pageBlock title="File Input">
<apex:pageBlockSection >
<apex:pageBlockSectionItem >
<apex:inputFile value="{!file.body}" filename="{!file.Name}"/>
<apex:commandButton action="{!showPreview}" value="Show Preview"/>
</apex:pageBlockSectionItem>
</apex:pageBlockSection>
</apex:pageBlock>
<apex:outputpanel id="docpanel">
{!result}
</apex:outputpanel>
</apex:form>
</apex:page>
This is giving me error of 7005, bad request.
We tried reproducing using the supplied code but it’s hard to reproduce properly without the remainder of the IDOLService controller code that has seemingly been omitted. We haven’t tried http posting multi-part forms from apex before (and a glance at some other questions suggests it’s not entirely simple) so it will take a bit of time to put together a working example.
Please can you send more information to idolondemand(at)hp.com so that the team can do a more in-depth review?
Regards,
hughesthe1st
(I work for HP)