I am relatively new to Java and have been stuck for a few days trying to get my application to 'POST' a HTTP request to Amazon's MWS API. I keep getting a 'SignatureDoesNotMatch' response and I cannot figure out why. I have used Amazon's MWS scratchpad extensively, and using it I don't have any trouble getting successful responses, so my keys etc are OK. The content parameters and base64 signature generated by the scratchpad match what my application generates, so I am confident that my application is correctly compiling the parameters and signature. When I hardcode the content parameters generated by the scratchpad into my application I get the 'SignatureDoesNotMatch'error response. I would be very grateful for any pointers from more experienced Java developers or anyone who has produced an application like mine working on Amazon's MWS.
The relevant section of my code is:
/*
* get amazon timestamp
*/
GetAmazonTimestamp timestampObj = new GetAmazonTimestamp();
String amazonTimestamp = null;
try {
amazonTimestamp = timestampObj.getTimestamp();
amazonTimestamp.replace(".000Z", "Z");
} catch (IOException e) {
e.printStackTrace();
}
/*
* create http parameters and initialise the signature value
*/
String URLendpoint = "https://mws.amazonservices.co.uk/orders/2011-01-01";
String param1 = "AWSAccessKeyId"; String value1 = "AKIAIZXBKLVSGBBQQL2A";
String param2 = "Action"; String value2 = "ListOrders";
String param3 = "LastUpdatedAfter"; String value3 = "2013-02-01T00:00:00Z";
String param4 = "MarketplaceId.Id.1"; String value4 = "A1F83G8C2ARO7P";
String param5 = "SellerId"; String value5 = "A3A2272JFHXROO";
String param6 = "SignatureMethod"; String value6 = "HmacSHA256";
String param7 = "SignatureVersion"; String value7 = "2";
String param8 = "Timestamp"; String value8 = amazonTimestamp;
String param9 = "Version"; String value9 = "2011-01-01";
String param10 = "Signature"; String value10 = null;
/*
* build sections of URL components for signature
*/
String URLforSignature = "POST\n" + "mws.amazonservices.co.uk\n" + "/Orders/2011-01-01\n" +
URLEncoder.encode(param1,"UTF-8") + "=" +
URLEncoder.encode(value1,"UTF-8") + "&" +
URLEncoder.encode(param2,"UTF-8") + "=" +
URLEncoder.encode(value2,"UTF-8") + "&" +
URLEncoder.encode(param3,"UTF-8") + "=" +
URLEncoder.encode(value3,"UTF-8") + "&" +
URLEncoder.encode(param4,"UTF-8") + "=" +
URLEncoder.encode(value4,"UTF-8") + "&" +
URLEncoder.encode(param5,"UTF-8") + "=" +
URLEncoder.encode(value5,"UTF-8") + "&" +
URLEncoder.encode(param6,"UTF-8") + "=" +
URLEncoder.encode(value6,"UTF-8") + "&" +
URLEncoder.encode(param7,"UTF-8") + "=" +
URLEncoder.encode(value7,"UTF-8") + "&" +
URLEncoder.encode(param8,"UTF-8") + "=" +
URLEncoder.encode(value8,"UTF-8") + "&" +
URLEncoder.encode(param9,"UTF-8") + "=" +
URLEncoder.encode(value9,"UTF-8");
/*
* hash and base64 encode the signature using the URLforSignature
*/
GetAmazonSignature signatureObj = new GetAmazonSignature();
value10 = signatureObj.getSignature(URLforSignature);
/*
* create the http post
*/
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(URLendpoint);
String line = null;
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
post.addHeader("Content-Type", "application/x-www-form-urlencoded");
nameValuePairs.add(new BasicNameValuePair(param1, value1));
nameValuePairs.add(new BasicNameValuePair(param2, value2));
nameValuePairs.add(new BasicNameValuePair(param3, value3));
nameValuePairs.add(new BasicNameValuePair(param4, value4));
nameValuePairs.add(new BasicNameValuePair(param5, value5));
nameValuePairs.add(new BasicNameValuePair(param6, value6));
nameValuePairs.add(new BasicNameValuePair(param7, value7));
nameValuePairs.add(new BasicNameValuePair(param8, value8));
nameValuePairs.add(new BasicNameValuePair(param9, value9));
nameValuePairs.add(new BasicNameValuePair(param10, value10));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8"));
HttpResponse response = client.execute(post);
BufferedReader rd = new BufferedReader(new InputStreamReader(
response.getEntity().getContent()));
line = "";
while ((line = rd.readLine()) != null) {
System.out.println(line);
}
}
Thanks for your help.
Thanks to those who helped me with this, but I finally worked out that "https://mws.amazonservices.co.uk/orders/2011-01-01" needs a capital "O" in orders. Amazon's development support agree that the 'SignatureDoesNotMatch' error message is not very helpful in this case and have said that they will look into it.
Thanks again
Why not use the Java Client libraries Amazon provides for MWS?
Go to MWS and click on the API you are interested in. You will see a Java Client library link where you can go and get the files you need. They contain examples and will handle the URL signing, parsing, and other work you would normally have to do yourself.
The way you construct URLforSignature seems okay.
You aren't showing your code for GetAmazonSignature, though. I would suspect the flaw to be in there. May be you forgot to base64-encode your result? Note that the MWS scratchpad shows both the hex signature as well as the base64 encoded one on the "Request Details" page. You should be able to find the flaw by comparing those details with your function results.
Related
I have a requirement to call a controller from java code itself. The controller is as follows,
#RequestMapping(value = "temp", method = RequestMethod.POST)
#ResponseBody
public String uploadDataFromExcel(#RequestBody Map<String, String> colMapObj, #ModelAttribute ReqParam reqParam) {
}
I am trying to call the above controller using http post as follows,
String url ="http://localhost:8081/LeadM" + "/temp/?searchData="+ reqParam.getSearchData()+" &exportDiscardRec=" + reqParam.isExportDiscardRec() + "&fileName=" + reqParam.getFileName() + "&sheetName=" + reqParam.getSheetName() + "&importDateFormat=" + reqParam.getImportDateFormat() + "&selectedAddressTypes="+ reqParam.getSelectedAddressTypes() + "&duplicatesHandleOn=" + reqParam.getDuplicatesHandleOn() + colMapObj;
HttpPost httpPost = new HttpPost(url);
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity entity = httpResponse.getEntity();
InputStream rstream = entity.getContent();
jsonObject = new JSONObject(new JSONTokener(rstream));
where reqParam is a class object is the class object and colMapObj is the map that I want to pass to the above controller. However when http post is executed it gives exception in the url.
If anybody knows the right way then please suggest, thank you.
This should work
#RequestMapping(value = "/temp", method = RequestMethod.POST)
#ResponseBody
public String uploadDataFromExcel(#RequestBody Map<String, String> colMapObj, #ModelAttribute ReqParam reqParam) {
}
and url should be
String url ="http://localhost:8081/LeadM" + "/temp?"+ reqParam.getSearchData()+" &exportDiscardRec=" + reqParam.isExportDiscardRec() + "&fileName=" + reqParam.getFileName() + "&sheetName=" + reqParam.getSheetName() + "&importDateFormat=" + reqParam.getImportDateFormat() + "&selectedAddressTypes="+ reqParam.getSelectedAddressTypes() + "&duplicatesHandleOn=" + reqParam.getDuplicatesHandleOn() + colMapObj;
URL dos not work with spaces.From your code above: " &exportDiscardRec="
To avoid such issues use URIBuilder or something similar if possible.
Now for the request, you are not building your request correctly for example you do not provide the body.
Check below example:
Map<String, String> colMapObj = new HashMap<>();
colMapObj.put("testKey", "testdata");
CloseableHttpClient client = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);
JSONObject body = new JSONObject(colMapObj);
StringEntity entity = new StringEntity(body.toString());
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Content-type", "application/json");
CloseableHttpResponse response = client.execute(httpPost);
System.out.println(response.getEntity().toString());
client.close();
More examples just google "apache http client post examples" (e.g. http://www.baeldung.com/httpclient-post-http-request)
Encode your query string.
String endpoint = "http://localhost:8081/LeadM/tmp?";
String query = "searchData="+ reqParam.getSearchData()+" &exportDiscardRec=" + reqParam.isExportDiscardRec() + "&fileName=" + reqParam.getFileName() + "&sheetName=" + reqParam.getSheetName() + "&importDateFormat=" + reqParam.getImportDateFormat() + "&selectedAddressTypes="+ reqParam.getSelectedAddressTypes() + "&duplicatesHandleOn=" + reqParam.getDuplicatesHandleOn() + colMapObj;
String q = URLEncoder.encode(query, "UTF-8");
String finalUrl = endpoint + q;
If this doesn't work, then encode individual params before concatenating.
On a side note
if you r running in same jvm then you can call method directly
if you own the the upload method then consider changing query string into form param
I am looking to interact with a Documentum Repository using their REST API. I would like to use the http-client 4.3 jars to perform this interaction.
I was hoping someone might have a sample that would help point me in the correct direction on how to interact with DCTM.
I am having trouble finding a clear and simple example of how to do this.
Thanks
I know it is a bit late to answer this question. But i want to answer to help those who still need a code for making requests to the rest api. Here is a full example of sending a post request to the rest api for starting a workflow.
For other needs you can check the Document called Documentum xCP Rest Services provided by EMC : https://support.emc.com/docu52500_Documentum-xCP-REST-Services-2.1-Development-Guide.pdf?language=en_US&request=akamai and compare with this example, change it according to it's needs.
UPDATE:
Also if you are not using xcp here is the Documentation for rest api without it emc.com/collateral/TechnicalDocument/docu57895.pdf
You can also check my answer here How can I use REST to copy an object in Documentum 7.x for geting object data and content from the rest api ( without xcp )
String strResponse = "";
String process_id = "system_name of the process you want to start";
String url = "Your App Url Here/processes/" + process_id;
String json = "{"+
"\"run-stateless\" : \"false\","+
"\"data\" :"+
" { "+
" \"variables\" : "+
" { \"Variable name\" : \"Variable value\" } "+
" } "+
"}";
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
BufferedReader rd = null;
CloseableHttpResponse cls = null;
try {
HttpPost request = new HttpPost(url);
// set timeouts as you like
RequestConfig config = RequestConfig.custom()
.setSocketTimeout(60 * 1000).setConnectTimeout(20 * 1000)
.setConnectionRequestTimeout(20 * 1000).build();
request.setConfig(config);
StringEntity params = new StringEntity(json);
request.addHeader("Accept", "application/json");
request.addHeader(
"Authorization",
"Basic "
+ com.documentum.xmlconfig.util.Base64
.encode("username here" + ":"
+ "password here"));
request.addHeader("Content-Type", "application/vnd.emc.xcp+json");
request.setEntity(params);
try {
cls = httpClient.execute(request);
HttpEntity entity = cls.getEntity();
rd = new BufferedReader(new InputStreamReader(
entity.getContent()));
String line = "";
while (line != null) {
line = rd.readLine();
strResponse += line;
}
strResponse = strResponse.trim().replace("\n", "");
String statusline = cls.getStatusLine().toString();
if (!statusline.contains("200") && !statusline.contains("201")) {
Log.write("Process is not started");
// log the strResponse or do something with it
} else {
System.out.println("Process started successfully");
}
} catch (Exception e) {
e.printStackTrace();
}
} finally {
// using commons-io-2.4.jar
IOUtils.closeQuietly(httpClient);
IOUtils.closeQuietly(cls);
IOUtils.closeQuietly(rd);
}
I'm simply trying to do a HttpGet.
Here is the string that is being passed:
fullString = "?nOne=" + node1 + "&nTwo=" + node2 + "&nThree=" + node3 + "&nFour=" + node4 + "&power=" + power + "&color=" + colorRGB;
All the variables are a single integer except for color which is 9 digits.
That string is passed to a function doing the following:
String get_url = URLEncoder.encode("http://192.168.30.80/" + str, "UTF-8");
HttpClient Client = new DefaultHttpClient();
HttpGet httpget;
ResponseHandler<String> responseHandler = new BasicResponseHandler();
httpget = new HttpGet(get_url);
String content = Client.execute(httpget, responseHandler);
I originally just tried:
String get_url = "http://192.168.30.80/" + str;
But that gave me an illegal character error. After trying urlencode now I get a:
java.lang.IllegalStateException: Target host must not be null, or set in parameters. scheme=null, host=null, path=http://192.168.30.80/[Ljava.lang.String;#1a50d830
Why can't it just be a string? (Obviously this is my first attempt with android/java)
Please help me understand what is going wrong, thanks.
URLEncoder.encode does not encode a full URL but should be used for the values of the GET parameters.
eg.
fullString = "?nOne=" + URLEncoder.encode(node1, "UTF-8");
fullString += "&nTwo=" + URLEncoder.encode(node2, "UTF-8");
Looking at the response, the path is not getting parsed to extract the scheme or host as these are both null.
Looking at the documentation, it should work from a string. Have you checked that the string is correctly encoded? It seems like it is unable to identify the scheme or host.
You could try inspecting the string value before it is passed to the HttpGet, or you might want to try using a URI.
URI address = new URI("http://192.168.30.80/" + str);
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet();
request.setURI(address);
HttpResponse response = client.execute(request);
I am stuck on a uploading issue. Server is in dotnet. Here is my iPhone code:
-(NSString *)encodeToBase64String:(UIImage *)image {
return [UIImagePNGRepresentation(image) base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
}
This works well, but when I am trying to upload by my Android app, it always returns error from server when there some special characters in url like (=).
See below the code:
Bitmap icon = BitmapFactory.decodeResource(this.contextParam.getResources(),
ByteArrayOutputStream bao = new ByteArrayOutputStream();
icon.compress(Bitmap.CompressFormat.JPEG, 90, bao);
byte[] ba = bao.toByteArray();
String ba1 = Base64.encodeToString(ba, Base64.DEFAULT);
Log.e("Data:", ba1);
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("username", "dsfsdfsd"));
nameValuePairs.add(new BasicNameValuePair("filenamewithextension", "upload.png"));
nameValuePairs.add(new BasicNameValuePair("newfilename", "Testing upload"));
nameValuePairs.add(new BasicNameValuePair("entityid", "10"));
nameValuePairs.add(new BasicNameValuePair("filestream", ba1));
Log.i(TAG, httppost.getURI().toString());
Log.d(TAG, nameValuePairs.toString());
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs,"UTF-8"));
String base64EncodedCredentials = Base64.encodeToString(CREDENTIALS.getBytes(), Base64.NO_WRAP);
httppost.addHeader("Authorization", "Basic " + base64EncodedCredentials);
httppost.addHeader("Content-Type", "application/largedata");
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
return getStringFromInputStream(response.getEntity().getContent());
} catch (ClientProtocolException e) {
Log.e(TAG, e.getLocalizedMessage());
} catch (IOException e) {
Log.e(TAG, e.getLocalizedMessage());
}
return responseString;
With above code server always returns with "Request Error". Why might this be happening?
Aside: I can't change the server implementation, I have to find a solution on the Android side.
I'm not 100% sure because you didn't post your log, but I had a similar issue with an App I was working on for iOS. For HTTP, they have encoding rules. You may need to "percent-escape encode" your HTTPPost.
For example:
www.website.com/security/authorizekey?url=www.website.com?user=bob
When the above link was used as my URL Post, the rules of HTTP truncated my Post so that the server only received "www.website.com/security/authorizekey?url=www.website.com?user=" and truncated my user "bob".
According to RFC 3986, the characters that should be permitted unescaped are the alphanumeric characters, plus "-", ".", "_", and "~":
2.3. Unreserved Characters
Characters that are allowed in a URI but do not have a reserved purpose are called unreserved. These include uppercase and lowercase letters, decimal digits, hyphen, period, underscore, and tilde.
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
See section 2 of the aforementioned RFC 3986 for more information.
Anyways, a solution might be similar to the following:
Potential Solution:
String query = URLEncoder.encode("apples oranges", "utf-8");
String url = "http://stackoverflow.com/search?q=" + query;
I am struggling with creating a plain text file on a server via HTTP PUT. I am using apache commons httpClient. My credentials are working but there is no body content in my request. What must I do to create the file like this? It works as intended when I try via hurl.it (ie setting my credentials, and setting a body). What I would like is the string "hej" to show in the file body. After getting this to work I intend to use a JSONString. The following code generates an empty file on the server (204 response):
HttpClient httpClient = new DefaultHttpClient();
String encoding = http_username + ":" + http_password;
encoding = Base64.encodeBase64String(encoding.getBytes());
HttpPut httpput = new HttpPut(http_path);
HttpEntity content=null;
try{
content = new StringEntity("hej");
}
catch(UnsupportedEncodingException e){
logger.error("Failed to Encode result");
}
logger.info("executing request " + httpput.getRequestLine());
try {
httpput.setHeader("Authorization", "Basic " + encoding);
//httpput.setHeader("Content-Type", "application/json; charset=utf-8");
httpput.setEntity(content);
HttpResponse response = httpClient.execute(httpput);
Header[] allHeaders = response.getAllHeaders();
for (Header h : allHeaders) {
logger.info(h.getName() + ": " + h.getValue());
}
} catch (Exception e) {
logger.error(e.getMessage());
}
I have tried both setting a content type and not doing it, no difference. What basic thing am I doing wrong?
Turns out that Base64.encodeBase64String appends a newline character at the end of the string, which throws everything off!
String encoding = http_username + ":" + http_password;
encoding = Base64.encodeBase64String(encoding.getBytes());
encoding= encoding.replace("\r\n", ""); //This fixes everything
Wow, that just took me a couple of days to figure out!