I'm using a SOAPHandler and here's my getHeaders method at the client side:
#Override
public Set<QName> getHeaders() {
String uri = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
QName security_hdr = new QName(uri, "Security", "wsse");
HashSet<QName> headers = new HashSet<QName>();
headers.add(security_hdr);
System.out.println("Headers: " + headers);
return headers;
}
The SystemOut in the above line produces this code, so definitely I did return something from my method:
Headers: [{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security]
However, when trying to capture the request in TCPMon, I don't see the header at all.
POST /ws/server HTTP/1.1
Content-type: text/xml;charset="utf-8"
Soapaction: ""
Accept: text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
User-Agent: JAX-WS RI 2.1.6 in JDK 6
Host: 127.0.0.1:4027
Connection: keep-alive
Content-Length: 170
<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body><ns2:getServerName xmlns:ns2="http://ws.ronixus.com/"/></S:Body>
</S:Envelope>
Any idea what I'm missing here? I've already commented out code from the other callback method handleMessage to make sure there's nothing overwriting the header.
Maybe try this in handleMessage, just to confirm?
SOAPHeader soapHeader = soapEnv.getHeader();
Iterator headers = soapHeader.extractAllHeaderElements();
while(headers.hasNext() ){
SOAPHeaderElement headerElement = (SOAPHeaderElement) headers.next();
Name name = headerElement.getElementName();
System.out.println(name)
}
Related
I make similar request with postman and rest-assured with the same credentials and receiving different status codes. The only header which accept server is application/json. Data and url are similar. I tried to add headers from postman, but it failed. ResstAssured.auth() isn't fit for me. Maybe someone have solution or faced this problem.
Code example:
public Response userLogin() {
JSONObject jsonObject = new JSONObject();
jsonObject.put("password", "pass");
jsonObject.put("account_name", "name");
jsonObject.put("email", "mail");
jsonObject.put("mfa_otp", 123456);
String url = "url";
return given()
.contentType(ContentType.JSON)
.body(jsonObject.toString())
.when()
.post(url)
.then()
.statusCode(200)
.extract()
.response();
}
Request:
Request method: POST
Request URI: url
Proxy: <none>
Request params: <none>
Query params: <none>
Form params: <none>
Path params: <none>
Content-Type=application/json; charset=UTF-8
Cookies: <none>
Multiparts: <none>
Body:
{
"password": "pass",
"account_name": "name",
"email": "mail"
}
Response:
HTTP/1.1 400 Bad Request
Date: Tue, 13 Apr 2021 19:27:16 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: nginx
X-Content-Type-Options: nosniff
X-Frame-Options: deny
Cache-Control: no-cache, no-store, must-revalidate
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: ETag, Link, X-Request-Id
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
X-Request-Id: 4e74caf3fa982d27cb827b5f7ebf6942
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
{
"status": "Bad Request",
"message": "Missing required parameter.",
"errors": [
{
"code": "required",
"field": "account_name"
}
]
}
Postman:
I figured out why It's happening every time, the Rest assured by default adding UTF-8 charset to content type.
Add this code to rest assured config method and you will be just fine, hope it will help to you.
private RestAssuredConfig decodeCharset = config().encoderConfig(encoderConfig().appendDefaultContentCharsetToContentTypeIfUndefined(false));
I am trying to call the API in Backend but I have some error that I have not an idea from what is causing by.
The problem started after I config the spring security in the backend.
The call should activate Preflighted requests OPTION
In my backend file, I have
#Configuration
#EnableWebSecurity
public class SpringSecurityConfigurationBasicAuth extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS,"/**").permitAll()
.anyRequest().authenticated()
.and()
// .formLogin().and()
.httpBasic();
}
}
and in the frontend, I have this part of the code.
executeHelloWorldServiceWithPathVariable(name) {
const basicAuthHeaderString = this.createBasicAuthenticationHttpHeader();
const headers = new HttpHeaders({
Authorization: basicAuthHeaderString
});
return this.http.get<HelloWorldBean>(`http://localhost:8080/hello-world/path-variable/${name}`,
{headers});
}
createBasicAuthenticationHttpHeader() {
const username = 'start';
const password = 'end';
const basicAuthHeaderString = 'Basic ' + window.btoa(username + ':' + password);
return basicAuthHeaderString;
}
In the backend, I have already include
#CrossOrigin(origins = "http://localhost:4200")
but still, I am not able to call this API
in the console, I should get something like an OPTION method but in fact, I get those:
General
Request URL: http://localhost:8080/hello-world/path-variable/start
Referrer Policy: no-referrer-when-downgrade
Response Header
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: keep-alive
Content-Length: 0
Date: Tue, 28 Jan 2020 11:11:49 GMT
Expires: 0
Keep-Alive: timeout=60
Pragma: no-cache
WWW-Authenticate: Basic realm="Realm"
WWW-Authenticate: Basic realm="Realm"
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
request head
Accept: application/json, text/plain, /
Accept-Encoding: gzip, deflate, br
Accept-Language: en,cs;q=0.9,en-US;q=0.8
Authorization: Basicc3RhcnQ6ZWVuZA==
Connection: keep-alive
Host: localhost:8080
Origin: http://localhost:4200
Referer: http://localhost:4200/welcome/start
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36
and in console, I see this error
Try to add cors policy in your security configuration:
#Configuration
#EnableWebSecurity
public class SpringSecurityConfigurationBasicAuth extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.cors();
http.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS,"/**").permitAll()
.anyRequest().authenticated()
.and()
// .formLogin().and()
.httpBasic();
}
}
to the class SpringSecurityConfigurationBasicAuth try to add this method
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
Got a websocket - see the authToken in the Cookie, in Java Spring how do you validate this authToken? I understand this authToken is passed down from the http layer to the websocket so I'm trying to validate that the websocket is being opened by our app and not by some other source.
Headers for Websocket:
GET ws://localhost:9999/somePath/websocket HTTP/1.1
Host: localhost:9999
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36
Upgrade: websocket
Origin: http://localhost
Sec-WebSocket-Version: 13
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Cookie: authToken=elFKMk5TckR0ZUNvdnZySUJxc2ZMdz09OklEZENrRFRySkp0U0ltVFdKU1RIZVE9PQ
Sec-WebSocket-Key: e//VDAjHSRjE810tCbIEyw==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Protocol: v10.stomp, v11.stomp, v12.stomp
I would like to validate that authToken in the HttpHandshakeInterceptor.beforeHandshake
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer
registry.addEndpoint(stompEndPoint).addInterceptors(new HttpHandshakeInterceptor()).setAllowedOrigins("*").withSockJS();
public class HttpHandshakeInterceptor implements HandshakeInterceptor
Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map attributes) throws Exception {
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
HttpSession session = servletRequest.getServletRequest().getSession();
attributes.put("sessionId", session.getId());
// validate token logic
}
return true;
}
I have an apache CXF client for a Microsoft WCF service, and I am attempting to send a file via MTOM. However, I keep getting a 400, and the error on the WCF side according to the partner is that there is an error creating the MTOM reader
I've traced the outbound message, and it looks like this:
INFO: Outbound Message
---------------------------
ID: 1
Address: https://someserver.com/ImportService.svc?wsdl
Encoding: UTF-8
Http-Method: POST
Content-Type: multipart/related; type="application/xop+xml"; boundary="uuid:1d46d7c9-047b-440d-928b-ab8689ab5e6f"; start="<root.message#cxf.apache.org>"; start-info="application/soap+xml; action=\"http://tempuri.org/IImportService/UploadFile\""
Headers: {Accept=[*/*], Accept-Encoding=[gzip;q=1.0, identity; q=0.5, *;q=0], Content-Encoding=[gzip]}
Payload: --uuid:1d46d7c9-047b-440d-928b-ab8689ab5e6f
Content-Type: application/xop+xml; charset=UTF-8; type="application/soap+xml; action=\"http://tempuri.org/IImportService/UploadFile\""
Content-Transfer-Encoding: binary
Content-ID: <root.message#cxf.apache.org>
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soap:mustUnderstand="true">
<wsse:UsernameToken wsu:Id="UsernameToken-e51a6fdd-5053-4aae-a9fb-363dde7d9e77">
<wsse:Username>blah#test.com</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">mypassword</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
<ns2:letterOptions xmlns="http://schemas.datacontract.org/2004/07/PublicServices.Import" xmlns:ns2="http://tempuri.org/">
<EnableQBPlanConsolidation>false</EnableQBPlanConsolidation>
<MASKSSN>true</MASKSSN>
<SRPrintedNumberofDays>2</SRPrintedNumberofDays>
<SuppressAllLetters>false</SuppressAllLetters>
<SuppressNewMemberLoginLetter>false</SuppressNewMemberLoginLetter>
<SuppressTakeOverLetterForTermed>false</SuppressTakeOverLetterForTermed>
<SuppressTerminationLetter>false</SuppressTerminationLetter>
</ns2:letterOptions>
<ns2:JobQueueType xmlns="http://schemas.datacontract.org/2004/07/PublicServices.Import" xmlns:ns2="http://tempuri.org/">Import</ns2:JobQueueType>
<Filename xmlns="http://tempuri.org/">testImport.csv</Filename>
<Action xmlns="http://www.w3.org/2005/08/addressing">http://tempuri.org/IImportService/UploadFile</Action>
<MessageID xmlns="http://www.w3.org/2005/08/addressing">urn:uuid:f380e4cc-225f-4b7d-bd46-6b5d607a59ca</MessageID>
<To xmlns="http://www.w3.org/2005/08/addressing">https://someserver.com/ImportService.svc?wsdl</To>
<ReplyTo xmlns="http://www.w3.org/2005/08/addressing">
<Address>http://www.w3.org/2005/08/addressing/anonymous</Address>
</ReplyTo>
</soap:Header>
<soap:Body>
<FileUploadMessage xmlns="http://tempuri.org/" xmlns:ns2="http://schemas.datacontract.org/2004/07/PublicServices.Import" xmlns:ns3="http://schemas.microsoft.com/2003/10/Serialization/">
<FileByteStream>
<xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:68e0408d-81da-496b-a06c-24a0459207d1-1#tempuri.org"/>
</FileByteStream>
</FileUploadMessage>
</soap:Body>
</soap:Envelope>
--uuid:1d46d7c9-047b-440d-928b-ab8689ab5e6f
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
Content-ID: <68e0408d-81da-496b-a06c-24a0459207d1-1#tempuri.org>
[VERSION],1.0
[NPM],552652222,1,Basic Client,Basic Client,Bob,Z,Jones,MR,bjones#test.com,402444555,,1234 Some street,,Omaha,NE,68123,,M,T,F,F
--uuid:1d46d7c9-047b-440d-928b-ab8689ab5e6f--
I've found plenty of other instances where other folks had the same issue:
https://coderanch.com/t/224995/java/Apache-CXF-MTOM-enabled-WCF
HTTP Bad Request error when requesting a WCF service contract
http://mail-archives.apache.org/mod_mbox/cxf-users/201211.mbox/%3CCAPXLCrCLkSkC8dQFeuU8DLY6gne1SOhwT9eMDxAUxLudnqU+YA#mail.gmail.com%3E
None of these were able to resolve my issue. I've tried multiple different versions of CXF and I get the same error with all of them.
This is a consolidated version of the code that is calling the service:
JaxWsProxyFactoryBean proxyFactory = new JaxWsProxyFactoryBean();
proxyFactory.setBindingId(SOAPBinding.SOAP12HTTP_MTOM_BINDING);
proxyFactory.setServiceClass(IImportService.class);
proxyFactory.setAddress(proxyEndpoint);
proxyFactory.getFeatures().add(new WSAddressingFeature());
IImportService importService = (IImportService) proxyFactory.create();
Client client = (Client) importService;
LetterOptions letterOptions = new LetterOptions();
letterOptions.setSRPrintedNumberofDays(2);
letterOptions.setMASKSSN(true);
letterOptions.setEnableQBPlanConsolidation(false);
List<Object> headerList = new ArrayList<>();
headerList.add(new Header(new QName("http://tempuri.org/", "letterOptions"),
letterOptions, new JAXBDataBinding(LetterOptions.class)));
headerList.add(new Header(new QName("http://tempuri.org/", "JobQueueType"), JobQueueType.IMPORT, new JAXBDataBinding(JobQueueType.class)));
headerList.add(new Header(new QName("http://tempuri.org/", "Filename"), "testImport.csv", new JAXBDataBinding(String.class)));
client.getRequestContext().put(Header.HEADER_LIST, headerList);
client.getEndpoint().getActiveFeatures().add(new LoggingFeature());
client.getInInterceptors().add(new GZIPInInterceptor());
client.getInInterceptors().add(new LogResponseInterceptor());
GZIPOutInterceptor outInterceptor = new GZIPOutInterceptor();
outInterceptor.setForce(true);
client.getOutInterceptors().add(outInterceptor);
Map props = new HashMap();
props.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
props.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
props.put(WSHandlerConstants.PW_CALLBACK_CLASS, PasswordCallbackHandler.class.getName());
props.put(WSHandlerConstants.USER, "blah#test.com");
WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(props);
client.getOutInterceptors().add(wssOut);
HTTPConduit conduit = (HTTPConduit) client.getConduit();
HTTPClientPolicy policy = conduit.getClient();
if(policy == null) {
policy = new HTTPClientPolicy();
}
policy.setAllowChunking(false);
FileUploadMessageReponse response = importService.uploadFile(fileUploadMessage);
One interesting tidbit is that I can copy the same request that is being logged into SoapUI, and it works fine.
Given we have made a multi part request. We are now needing to ad a content-id. Below is the code that we were trying to use to create the multipart request:
MultipartEntity mpEntity = new MultipartEntity();
StringBody body;
try
{
body = new StringBody( xml, "application/xml", Charset.forName( "UTF-8" ) );
byte[] data = getBytesFromFile( image );
ByteArrayBody bab = new ByteArrayBody( data, "image/jpeg", "test_image_cid" );
mpEntity.addPart( "body", body );
mpEntity.addPart( "test_image_cid", bab );
} catch ( UnsupportedEncodingException e )
{
e.printStackTrace();
}
HttpPost request = new HttpPost("http://10.1.1.1");
request.addHeader( "Authorization", authorization_header_values );
request.addHeader( "Content-Type", "Multipart/Related" );
request.setEntity( mpEntity );
return request;
This is what the webservice that we are calling has requested:
<?xml version="1.0" encoding="utf-8"?> <request method="receipt.create">
<receipt>
<expense_id>1</expense_id> <!-- id of expense -->
<image>cid:xxxxxxxxxxxxx</image> <!-- content-id used on the related binary content -->
</receipt>
</request>
This is what we are getting back from the server for debugging:
POST / HTTP/1.1
Authorization: OAuth realm="", oauth_version="1.0", oauth_consumer_key="key", oauth_token="token", oauth_timestamp="1358197676614", oauth_nonce="1111111", oauth_signature_method="PLAINTEXT", oauth_signature="signature"
Content-Type: Multipart/Related
User-Agent: agent
Content-Length: 2336363
Host: 10.1.1.1
Connection: Keep-Alive
--HPeiFlrswQmM8Mi1uoWpzJRfrnp3AMtZjpCdt
Content-Disposition: form-data; name="body"
Content-Type: application/xml; charset=UTF-8
Content-Transfer-Encoding: 8bit
<?xml version='1.0' encoding='UTF-8' ?>
<request method="receipt.create">
<receipt>
<expense_id>979</expense_id>
<image>cid:test_image_cid</image>
</receipt>
</request>
--HPeiFlrswQmM8Mi1uoWpzJRfrnp3AMtZjpCdt
Content-Disposition: form-data; name="test_image_cid"; filename="test_image_cid"
Content-Type: image/jpeg
Content-Transfer-Encoding: binary
We are stuck in figuring out how to add the Content-ID to this request. Is there anything obvious that is missing in this call? IS there another way to build this request? Thanks for any advice!
To add the Content-Id, or any other field for that matter, you have to use a FormBodyPart. Simply put, split up these lines:
ByteArrayBody bab = new ByteArrayBody( data, "image/jpeg", "test_image_cid" );
mpEntity.addPart( "body", body );
Into these lines:
ByteArrayBody bab = new ByteArrayBody( data, "image/png", "byte_array_image" );
FormBodyPart fbp = new FormBodyPart( "form_body_name", bab );
fbp.addField( "Content-Id", "ID_GOES_HERE" );
mpEntity.addPart( fbp );
And that should do it for you!