JAX-WS sending empty value after explicitly adding SOAPAction header - java

I have made webservice client with NetBeans 8.2 wizard from an existing WSDL document. Java8 and JAX-WS 2.2.9 is used.
As far as I understand everything works with the wizard created code as expected but the query is missing value from "SOAPAction" header which is requirement to have value for the query to work. The header key exists but value is empty string: SOAPAction: "" when it should be SOAPAction = "SendReports"
I have tried using this:
Map<String, List<String>> requestHeaders = new HashMap<>();
requestHeaders.put("SOAPAction", Arrays.asList("sendReports"));
sourceDispatch.getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, requestHeaders);
-> which results also in empty value. If I put "SOAPAction_2" & "sendReports", that header works correct but obviously the header key is wrong and wont solve my problem. Something overwrites my value afterwards?
The webservice method has annotation:
#WebMethod(operationName = "SendReports", action = "SendReports")
Any tips on what could I try next?
I saw many posts suggesting using BindingProvider but I cannot use com.sun.* packages for reasons left unexplained.

Finally found a working solution.
I created a Web service Dispatch client with Netbeans (as originally) and had to add SOAPACTION_USE_PROPERTY and SOAPACTION_URI_PROPERTY.
These I had tried before as System properties but seemed not to work that way.
Here is the working snippet:
public void sendReports() throws IOException {
ReportService service = new ReportService();
QName portQName = new QName("http://URL/ReportService", "ReportService");
req = readFile("C:/temp/myFile.xml", "UTF-8");;
try {
// Call Web Service Operation
Dispatch<Source> sourceDispatch = null;
sourceDispatch = service.createDispatch(portQName, Source.class, Service.Mode.PAYLOAD);
Map<String, Object> map = sourceDispatch.getRequestContext();
map.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
map.put(BindingProvider.SOAPACTION_URI_PROPERTY, "SendReports");
Source result = sourceDispatch.invoke(new StreamSource(new StringReader(req)));
} catch (Exception ex) {
// TODO handle custom exceptions here
}
}

Related

org.bouncycastle.cms.CMSException: content-type attribute value does not match eContentType

I'm currently building a TimeStamp server using BouncyCastle. Server is working well but on the client side, when I want to validate the TimeStampResponse received I'm getting the following error:
org.bouncycastle.cms.CMSException: content-type attribute value does
not match eContentType
On the server side, I'm including the content-type attribute like this:
ASN1EncodableVector signedAttributes = new ASN1EncodableVector();
signedAttributes.add(new Attribute(CMSAttributes.contentType, new DERSet(new ASN1ObjectIdentifier("1.2.840.113549.1.7.1"))));
signedAttributes.add(new Attribute(CMSAttributes.messageDigest, new DERSet(new DEROctetString(request.getMessageImprintDigest()))));
signedAttributes.add(new Attribute(CMSAttributes.signingTime, new DERSet(new DERUTCTime(timeStampDate))));
AttributeTable signedAttributesTable = new AttributeTable(signedAttributes);
signedAttributesTable.toASN1EncodableVector();
//Linking Attribute Table to the signBuilder (linked to JKS Certificate)
DefaultSignedAttributeTableGenerator signedAttributeGenerator = new DefaultSignedAttributeTableGenerator(signedAttributesTable);
signBuilder.setSignedAttributeGenerator(signedAttributeGenerator);
signBuilder.setUnsignedAttributeGenerator(new SimpleAttributeTableGenerator(new AttributeTable(new Hashtable<String, String>())));
......
and on the client side:
Collection<X509CertificateHolder> tstMatches = response.getTimeStampToken().getCertificates().getMatches(response.getTimeStampToken().getSID());
X509CertificateHolder holder = tstMatches.iterator().next();
java.security.cert.X509Certificate tstCert = new JcaX509CertificateConverter().getCertificate(holder);
System.out.println("Cert Date exp: "+tstCert.getNotAfter());
SignerInformationVerifier siv = new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(tstCert);
AttributeTable att = response.getTimeStampToken().getSignedAttributes();
System.out.println("Content-type: "+att.get(CMSAttributes.contentType).getAttrValues().getObjectAt(0));
if(bytesToHex(response.getTimeStampToken().getTimeStampInfo().getMessageImprintDigest()).equals(bytesToHex(digest))) {
System.out.println("TimeStamp is valid, imprint is identical");
}
try {
response.getTimeStampToken().validate(siv);
}catch(Exception e) {
System.out.println("Still getting issue with Content Type: "+e.toString());
}
It seems that I include correctly the content-type in my TimeStampToken ("1.2.840.113549.1.7.1") but I don't know where is the eContentType and don't know where I can check it.
EDIT 1: May be I'm not clear in my answer...I'll try to reformulate...
How can I access eContentType of a TimeStampToken ?
What BouncyCastle is comparing ?
After multiple readings, I've seen that adding contentType Attribute is making this kind of error, as I'm already building the TimeStampResponse based on the request, the content type is already taken into account.
It make a conflict on the BouncyCastle Library, so by removing the line :
//signedAttributes.add(new Attribute(CMSAttributes.contentType, new DERSet(new ASN1ObjectIdentifier("1.2.840.113549.1.7.1"))));
everything works fine, my TimeStampResponse is validated correctly.

Jaxb unmarshal works on debug but not in runtime

I'm trying to use the ACS (Cisco Secure Access Control System) to manage users in the network equipment using code. I've downloaded the examples provided with the product and built upon that, my code.
When I test it in debug mode, everything works great but when I put my .class files in Jboss Web Server and try to execute the main method from another application, I get this error:
unexpected element (uri:identity.rest.mgmt.acs.nm.cisco.com", local:"user"). Expected elements are (none)
my code is:
private static User getUserByName(RestFacade restFacade, String name)
{
User user = null;
String url = "/Rest/Identity/User/name/";
url = url.concat(name);
HttpResponse response = restFacade.get(url);
try {
byte buffer[] = new byte[8192];
int read = 0;
StringBuffer responseBody = new StringBuffer();
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream content = response.getEntity().getContent();
while ((read = content.read(buffer)) != -1) {
responseBody.append(new String(buffer, 0, read));
}
}
ByteArrayInputStream bais = new ByteArrayInputStream(responseBody
.toString().getBytes());
Unmarshaller unmarshaller = JAXBContext.newInstance(User.class).createUnmarshller();
user = (User) unmarshaller.unmarshal(bais);
} catch (Exception e) {
e.printStackTrace();
}
return user;
}
Almost every solution I found for such an error, said to change something in the Rest method I'm trying to invoke or change the xsd, but I don't have access to those..
The weird thing is that it works when I debug from Eclipse but not on runtime. Maybe there's a different version to JAXB I'm using? How can I be sure which jar loads up?
Thank you,
Igor.
That sounds like your development environment you use to debug and your target application server have a different version of either the JAXB classes / library and/or the used XSDs.
The documentation (http://www.cisco.com/c/en/us/td/docs/net_mgmt/cisco_secure_access_control_system/5-3/sdk/acs_sdk/rest.html) specifies the three XSDs (Common, Identity and Query).
Have you verified the version you have (or have downloaded) match the generated JAXB classes on the target application server?

multipartentity that seems to be multiple levels deep?

I am having an issue with a client that is using some crazy (it likely isn't crazy, I really mean unfamiliar to myself ;) ) ruby rails plugin to handle the uploading of images with data attached. The way they say the server is looking for the information is
{
"objectname"{
"field"=>"value"
"field"=>"value"
"photo"=>#<ActionDispatch::Http::UploadedFile:0x00000004864fd0 #original_filename="avatar.png", #content_type="image/png",
#headers="Content-Disposition: form-data; name=\"aPhoto\"; filename=\"avatar.png\"\r\nContent-Type: image/png\r\n",
#tempfile=#<File:/tmp/RackMultipart20140211-8-1456165191981>
}
}
the problem is that with MultiPartEntity (which is what they say to use) all I can do is get the server to see this
{
"field"=>"value"
"field"=>"value"
"photo"=>#<ActionDispatch::Http::UploadedFile:0x00000004864fd0 #original_filename="avatar.png", #content_type="image/png",
#headers="Content-Disposition: form-data; name=\"aPhoto\"; filename=\"avatar.png\"\r\nContent-Type: image/png\r\n",
#tempfile=#<File:/tmp/RackMultipart20140211-8-1456165191981>
}
that extra layer of wrapping is proving difficult. here is how I have it, how can I achieve that extral layer under that key "objectname"?
MultipartEntity multiPartEntity = new MultipartEntity(HttpMultipartMode.STRICT, null, Charset.forName("UTF-8"));
ByteArrayBody imageByteArrayBody = new ByteArrayBody(imageBytes, "image/png", "avatar.png");
FormBodyPart imageFormBodyPart = new FormBodyPart("photo", imageByteArrayBody);
// sanity checks to make sure the headers are right
imageFormBodyPart.addField("Content-Disposition", "form-data; name=\"aPhoto\"");
imageFormBodyPart.addField("name", "aPhoto");
imageFormBodyPart.addField("filename", "avatar.png");
imageFormBodyPart.addField("Content-Type", "image/png");
// add the image body part to the multipart entity
multiPartEntity.addPart(imageFormBodyPart);
// add customer data
Map<String, String> customerMap = user.getUserMap();
// loop through the fields
for (Map.Entry<String, String> entry : customerMap.entrySet())
{
// create a new form part with the key as the name and the value as the value
FormBodyPart body = new FormBodyPart(entry.getKey(), new StringBody(entry.getValue()));
// sanity checking the headers are right
body.addField("Content-Disposition", "form-data; name=\"" + entry.getKey() + "\"");
body.addField(entry.getKey(), entry.getValue());
// add the part to the multipart entity
multiPartEntity.addPart(body);
}
postRequest.setEntity(multiPartEntity);
postRequest.setHeader(KEY_AUTHORIZATION, VALUE_AUTHORIZATION);
HttpResponse response = httpClient.execute(postRequest);
I know this is kind of late. But I've stumbled upon a similar issue recently. The solution that worked for me is adjusting the code on the rails end to remove that extra param wrapping. As per my research nested parts are not possible with MultipartEntity

How do I send JSON to an external API using RestEasy?

I need to send a JSON body to https://mandrillapp.com/api/1.0//messages/send-template.json . How do I do this using RestEasy in Java? This is what I have so far:
ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target("https://mandrillapp.com/api/1.0//messages/send-template.json");
How do I actually send the JSON?
Once you have the ResteasyWebTarget, you need to get the Invocation
Invocation.Builder invocationBuilder = target.request("text/plain").header("some", "header");
Invocation incovation = invocationBuilder.buildPost(someEntity);
invocation.invoke();
where someEntity is some instance of Entity<?>. Create one with
Entity<String> someEntity = Entity.entity(someJsonString, MediaType.APPLICATION_JSON);
Read this javadoc.
This is for 3.0 beta 4.
This is a bit old question, but I found it looking for something similar on Google, so this is my solution, using RestEasy client 3.0.16:
I'll use a Map object to be sent but you can use whatever JavaBean that Jackson provider can convert to JSON.
BTW, you'll need add as dependency the resteasy-jackson2-provider lib.
ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target("http://server:port/api/service1");
Map<String, Object> data = new HashMap<>();
data.put("field1", "this is a test");
data.put("num_field2", 125);
Response r = target.request().post( Entity.entity(data, MediaType.APPLICATION_JSON));
if (r.getStatus() == 200) {
// Ok
} else {
// Error on request
System.err.println("Error, response: " + r.getStatus() + " - "+ r.getStatusInfo().getReasonPhrase());
}
I've never used this framework, but according to an example at this url, you should be able to make a call like this:
Client client = ClientBuilder.newBuilder().build();
WebTarget target = client.target("http://foo.com/resource");
Response response = target.request().get();
String value = response.readEntity(String.class);
response.close(); // You should close connections!
The 3rd line seems to be the answer you're looking for.

SOAP result null?

I have problem with my soap client. I have generate client part from wsdl using apache cxf.
I'm using Netbeans IDE and Maven. I also created HeaderHandler where I print soap response and it seems to be valid. But when I call web service method from my client a always get null value without any exception.
Any idea?
Thanks.
Update:
link to wsdl http://carecoprod.blueway.fr:8180/engine53/52/WSDL?name=AAA00_WsB2B&version=1&type=EAII
Client code:
{
AAA00WsB2B ss = new AAA00WsB2B(wsdlURL, SERVICE_NAME);
HeaderHandlerResolver h = new HeaderHandlerResolver();
ss.setHandlerResolver(h);
AAA00WsB2BPortType port = ss.getAAA00WsB2BPort();
System.out.println("Invoking aaa00WsB2B...");
AAA00WsB2BIN input = new AAA00WsB2BIN();
VarAAA v = new VarAAA();
v.setLogin("*******");
v.setImmat("*******");
v.setTypeReq("******");
v.setMdp("*******");
input.setVarAAA(v);
AAA00WsB2BOUT _aaa00WsB2B__return = new ObjectFactory().createAAA00WsB2BOUT();
_aaa00WsB2B__return = port.aaa00WsB2B(input);
System.out.println("aaa00WsB2B.result="+_aaa00WsB2B__return.getVarAAARetourWs().getCO2());
}

Categories