How to disable cxf SOAP client use multipart request - java

I have to call a proprietary service that does not support multipart requests, I'm not sending any attachments but cxf seems to create a multipart request
POST /endpoint HTTP/1.1
Content-Type: multipart/related; type="text/xml"; boundary="uuid:86ebef4f-fc2a-431b-a21b-37e86b4901f9"; start="<root.message#cxf.apache.org>"; start-info="text/xml"
Accept: */*
Authorization: Basic U1dHMTAwNTA6MTIzNDU1
SOAPAction: "XYZ.0050"
User-Agent: Apache-CXF/3.3.6
Cache-Control: no-cache
Pragma: no-cache
Host: localhost:8082
Connection: keep-alive
Content-Length: 2134
--uuid:86ebef4f-fc2a-431b-a21b-37e86b4901f9
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: binary
Content-ID: <root.message#cxf.apache.org>
[etc...]
I've noticed a non-multipart request works fine
POST /endpoint HTTP/1.1
Content-Type: text/xml;charset=UTF-8
Accept: */*
Authorization: Basic U1dHMTAwNTA6MTIzNDU1
Cache-Control: no-cache
Connection: keep-alive
Host: localhost:8082
Pragma: no-cache
SOAPAction: "XYZ.0050"
User-Agent: Apache-CXF/3.3.6
Content-Length: 2114
[etc...]
How do I force cxf to use a non-multipart request?

it looks like cxf creates a multipart any time there is a #XmlAttachmentRef / DataHandler attribute, in my case it is never used so I removed it from my classes.
a better solution would be to remove the SwAOutInterceptor from the interceptor chain by definining an interceptor remover
class InterceptorRemover : AbstractSoapInterceptor(Phase.PRE_LOGICAL) {
init {
addBefore(SwAOutInterceptor::class.java.name)
}
override fun handleMessage(message: SoapMessage?) {
if (message != null) {
val res = message.interceptorChain.firstOrNull() { it is SwAOutInterceptor }
if (res != null) {
message.interceptorChain.remove(res)
}
}
}
}
and add it to the chain:
val client = ClientProxy.getClient(port)
client.outInterceptors.add(InterceptorRemover())

Related

403 Forbidden error from SprintBoot RestTemplate but working fine from Postman

With a given token, Postman can hit the Microsoft Graph API successfully, whereas the SpringBoot RestTemplate gives the 403 Forbidden error.
From Postman:
GET https://graph.microsoft.com/beta/me/profile/
Authorization: Bearer <token>
User-Agent: PostmanRuntime/7.26.8
Cache-Control: no-cache
Host: graph.microsoft.com
Accept-Encoding: gzip, deflate
Connection: keep-alive
Accept: */*
From SpringBoot Apache Logs:
GET /beta/me/profile/ HTTP/1.1
Authorization: Bearer <token>
Cache-Control: no-cache
User-Agent: PostmanRuntime/7.26.8 (I hardcoded it to make everything same as postman)
Host: graph.microsoft.com
Connection: Keep-Alive
Accept-Encoding: gzip,deflate
Accept: */*
Here is the sample code that I was using:
#GetMapping("/test")
public String test() {
String token = "removed for now";
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setBearerAuth(token);
httpHeaders.setAccept(Arrays.asList(MediaType.ALL));
httpHeaders.setCacheControl("no-cache");
httpHeaders.add(HttpHeaders.USER_AGENT, "PostmanRuntime/7.26.8");
HttpEntity httpEntity = new HttpEntity(httpHeaders);
ResponseEntity<String> exchange = restTemplate.exchange("https://graph.microsoft.com/beta/me/profile/",
HttpMethod.GET,
httpEntity,
String.class);
return exchange.getBody();
}
I tried several suggestions but couldn't figure it out. Any idea on what might be going wrong?

Jax-WS with NTLM authentification

As I read Jax-ws can authenticate with NTLM, but I have a problem;
First of all I create MyAuthenticator java class as describe in java documentation(see:
http://docs.oracle.com/javase/7/docs/technotes/guides/net/http-auth.html).
when I try to connect with soapUI everything is Ok, see request header:
Request Headers Value
(Request-Line) POST /Online/OnlineServices.asmx HTTP/1.1
Content-Type text/xml;charset=UTF-8
SOAPAction "http://CTL.COM/OnlineServices/AcquireTicket"
Host 172.22.2.144:8000
Connection Keep-Alive
User-Agent Apache-HttpClient/4.1.1 (java 1.5)
Authorization NTLM TlRMTVNTUAADAAAAGAAYAEAAAACgAKAAWAAAAAYABgD4AAAAGAAYAP4AAAAMAAwAFgEAAAAAAAAiAQAA
Accept-Encoding gzip, deflate
Content-Length 702
when I try to connect with java, I got 500 Internal server error, see header:
Request Headers Value
(Request-Line) POST /Online/OnlineServices.asmx HTTP/1.1
SOAPAction "http://CTL.COM/OnlineServices/AcquireTicket"
Accept text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Content-Type text/xml;charset="utf-8"
User-Agent JAX-WS RI 2.1.4-b01-
Host 172.22.2.144:8000
Connection keep-alive
Authorization NTLM TlRMTVNTUAADAAAAGAAYAIwAAAD8APwApAAAAAYABgBYAAAAIgAiAF4AAAAMAAwAgAAAAAAAAACgAQAABYKIogoAOTgAAAAP5/lqdc43ElnLlEh5ASEkQlUARgBDAGUAdgBnAGUAbgBpAC4AbwByAG0AbwB0AHMAYQBkAHoAZQBQAEMALQAyADMAMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABXZ
Accept-Encoding gzip, deflate
Content-Length 443
this is my code :
Authenticator.setDefault(new MyAuthenticator(domain + "\\kuser","kpass"));
OnlineServicesSoap onlineServicesSoap = new OnlineServices(url,qName).getOnlineServicesSoap();
Map<String, List<String>> headers = new HashMap<String, List<String>>(); headers.put("Content-Type", Collections.singletonList("text/xml;charset=UTF-8"));
headers.put("Accept-Encoding", Collections.singletonList("gzip, deflate"));
((BindingProvider)onlineServicesSoap).getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, headers);
try {
AcquireTicketResponse acquireTicketResponse =
onlineServicesSoap.acquireTicket(acqTicket);
} catch (RuntimeException ex) {
System.out.println(ex.getMessage() + ex.getCause());
}
I searched a lot and found some posts suggesting to do NTLM authentication but I couldn't to connect.. I don't want to use axis implementation

OAuth2 oltu client

I'm building my oauth2-protecet webservice, and a client. For webservice I used spring security implementation, and used this as example. For client I'm trying out apache oltu library. Here's my snippet:
OAuthClientRequest request = OAuthClientRequest.tokenLocation
("http://localhost:8080/oauth/token")
.setGrantType(GrantType.CLIENT_CREDENTIALS)
.setClientId("clientapp")
.setClientSecret("123456")
.buildHeaderMessage();
OAuthAccessTokenResponse oAuthResponse = cli.accessToken(request);
System.out.println(oAuthResponse.getAccessToken());
It does not work. While this
curl -X POST -vu clientapp:123456 --data "grant_type=client_credentials&client_secret=123456&client_id=clientapp" http://localhost:8080/oauth/token
works perfectly well. Here's the curl request:
POST /oauth/token HTTP/1.1
Authorization: Basic Y2xpZW50YXBwOjEyMzQ1Ng==
User-Agent: curl/7.35.0
Host: localhost:8080
Accept: */*
Content-Length: 70
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_secret=123456&client_id=clientapp
as you can see, I used Basic authentication with curl and it worked(even though suggested authentication type is Bearer).
And here's oltu packet:
POST /oauth/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer client_credentials123456clientapp
User-Agent: Java/1.8.0_51
Host: localhost:8080
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
Content-Length: 4
null
I'm nor sure how bearer authorization is supposed to work, but this packet looks all wrong.
I also tried to use buildBodyMessage() and buildQueryMessage() instead of buildHeaderessage() as was suggested in this post, but it's no good either.
This line doesnt look very healthy:
Authorization: Bearer client_credentials123456clientapp
I created a test server with Oltu, basically a servlet:
OAuthResponse oauthResponse = OAuthASResponse
.tokenResponse(HttpServletResponse.SC_OK)
.setAccessToken(accessToken)
.setExpiresIn(Integer.toString(expires))
.setRefreshToken(refreshToken)
.buildJSONMessage();
response.setStatus(oauthResponse.getResponseStatus());
response.setContentType("application/json");
And for the client I got:
OAuthClientRequest request = OAuthClientRequest
.tokenLocation("http://localhost:8083/OltuServer/token")
.setGrantType(GrantType.CLIENT_CREDENTIALS)
.setClientId("clientapp")
.setClientSecret("123456")
.buildQueryMessage();
OAuthAccessTokenResponse oAuthResponse = oAuthClient.accessToken(request);
System.out.println(oAuthResponse.getAccessToken());
The main difference from your code is buildQueryMessage(). Using buildHeaderMessage() I get an exception on the server
OAuthProblemException {error='invalid_request', description='Missing grant_type parameter value' ... }
But I see that Oltu is at version 1.0.1 now while I've been testing on 1.0.0. That version might behave different.
The following appeared to work for me:
OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
OAuthClientRequest bearerClientRequest = OAuthClientRequest.tokenLocation("http://localhost/rest/auth")
.setUsername("userid")
.setPassword("Password01")
.buildQueryMessage();
bearerClientRequest.setHeader(OAuth.HeaderType.CONTENT_TYPE, "multipart/form-data");
OAuthResourceResponse resourceResponse = oAuthClient.resource(bearerClientRequest, OAuth.HttpMethod.POST, OAuthResourceResponse.class);

Spring MVC: wrong encoding of downloaded file

I'm trying to understand a strange behaviour in pdf file download using spring mvc servlet.
Here is the controller code used to download files:
#RequestMapping(value = "/handler/{id}", method = RequestMethod.GET)
public HttpEntity<byte[]> report(#PathVariable("id") Long id,
HttpServletResponse response,
HttpServletRequest request) {
byte[] bytes = service.reportById(id);
return DownloadUtil.downloadFile(response, "application/pdf",
"Filename.pdf", bytes);
}
public static HttpEntity<byte[]> downloadFile(
final HttpServletResponse response,
final String contentType,
final String fileName,
final byte[] item){
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.valueOf(contentType));
header.set("Content-Disposition", "inline; filename=\"" + fileName +"\"");
header.set("Content-Transfer-Encoding", "application/octet-stream");
header.setContentLength(item.length);
return new HttpEntity<byte[]>(item, header);
}
When pdf is displayed in chrome pdf viewer it works. Here request/response headers:
Request:
GET /path/19649/download HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36
Referer: http://path/byDitta
Accept-Encoding: gzip, deflate, sdch
Accept-Language: it,en-US;q=0.8,en;q=0.6
Cookie: JSESSIONID=09CEA1438ACED879CDD96877BB536022; _ga=GA1.1.2013320496.1416898514
Response:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Disposition: inline; filename="file.pdf"
Content-Transfer-Encoding: application/octet-stream
Content-Type: application/pdf;charset=UTF-8
Content-Length: 296750
Date: Tue, 10 Mar 2015 09:39:05 GMT
When I save pdf displayed in pdf viewer I've this request/response header:
Request:
GET /path/19649/download HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Referer: /path/19649/download
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: it,en-US;q=0.8,en;q=0.6
Cookie: JSESSIONID=09CEA1438ACED879CDD96877BB536022; _ga=GA1.1.2013320496.1416898514
Response:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Disposition: inline; filename="file.pdf"
Content-Transfer-Encoding: application/octet-stream
Content-Type: application/pdf;charset=UTF-8
Content-Length: 296750
Date: Tue, 10 Mar 2015 09:40:29 GMT
The difference is in accept request header, I think. It is missed in save pdf request.
The problem is that, when this file is saved it has a wrong encoding and so results to be damaged.
The strange thing is that I use the ~same code in another project to do the same thing and it works. So I think, may be something in servlet config?
How can I force right download encoding?
From the comment:
Comparing file size, working pdf is 227403 bytes, the other is 303206 bytes
This suggests the data is Base64 encoded. I don't see why this would happen; most of the time, you get this effect when the server thinks the client can't handle binary data (like when you do an AJAX request).
[EDIT] Install a proxy server like Fiddler which allows you to see the raw data which your server sends to the browser. Try to create only a small PDF, to make this easier.
With these tools, you can find out who encodes the data.
If your pdf file generated well, I think you should try in this way:
#RequestMapping(value = "clients/city")
#ResponseBody
private OutputStream getCity(HttpServletRequest request,HttpServletResponse response) throws IOException, JRException {
String path=request.getRealPath("resources/files");
createFileService.SpravkaCity(path);
// response.setContentType("text/plain");
// response.setHeader("Content-Disposition", "attachment; filename=reestr.xls");
File f=new File(path+"/city.pdf");
response.setContentType("application/pdf");
// response.setHeader("Content-Transfer-Encoding", "binary");
response.setHeader("Content-Length", String.valueOf(f.length()));
response.setHeader("Content-Disposition", "inline; filename=city.pdf");
Path p = Paths.get(path+"/city.pdf");
response.getOutputStream().write(Files.readAllBytes(p));
return response.getOutputStream();
}
Hope it will help you.

Spring ws Operation 'message' is not defined in the WSDL for this service

Hi I'm trying to create a soap client using spring-ws. I tried whith the following code:
public void test1() {
WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
webServiceTemplate.setDefaultUri("the url of my web service");
StreamSource source = new StreamSource(new StringReader("<message xmlns=\"http://tempuri.org\">Hello Web Service World</message>"));
StreamResult result = new StreamResult(System.out);
webServiceTemplate.sendSourceAndReceiveToResult(source, result);
}
from http://docs.spring.io/spring-ws/site/reference/html/client.html and I got this excetion.
org.springframework.ws.soap.client.SoapFaultClientException: Operation 'message' is not defined in the WSDL for this service
at org.springframework.ws.soap.client.core.SoapFaultMessageResolver.resolveFault(SoapFaultMessageResolver.java:37)
at org.springframework.ws.client.core.WebServiceTemplate.handleFault(WebServiceTemplate.java:774)
at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:600)
at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:537)
at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:492)
at org.springframework.ws.client.core.WebServiceTemplate.sendSourceAndReceiveToResult(WebServiceTemplate.java:436)
at org.springframework.ws.client.core.WebServiceTemplate.sendSourceAndReceiveToResult(WebServiceTemplate.java:427)
at org.springframework.ws.client.core.WebServiceTemplate.sendSourceAndReceiveToResult(WebServiceTemplate.java:417)
at Test.test1
How to fix it ?
Ok I solve it, in the question there is juste an exemple of a case where the error occured,
I used netcat as client and got this result:
POST / HTTP/1.1
Accept-Encoding: gzip
Accept: text/xml, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
SOAPAction: ""
Content-Type: text/xml; charset=utf-8
Cache-Control: no-cache
Pragma: no-cache
User-Agent: Java/1.7.0_55
Host: localhost:1234
Connection: keep-alive
Content-Length: 154
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><message xmlns=\"http://tempuri.org\">Hello Web Service World</message></SOAP-ENV:Body></SOAP-ENV:Envelope>
In this test the message was not what the server was expecting. But I understood the problem.
I thought that spring ws wasn't creating the soap envelope, so the message had two envelopes.

Categories