I'm having this problem when consuming a SOAP webservice from a Quarkus application.
The error I'm getting is:
Caused by: org.apache.cxf.transport.http.HTTPException: HTTP response '403: (POST http://mydevelopserver/XISOAPAdapter/MessageServlet?senderParty=&senderService=hidden01&receiverParty=&receiverService=&interface=SI_SAP_MaestroProveedores_sync_out&interfaceNamespace=hidden2) 403' when communicating with http://mydevelopserver/XISOAPAdapter/MessageServlet?senderParty=&senderService=hidden01&receiverParty=&receiverService=&interface=SI_SAP_MaestroProveedores_sync_out&interfaceNamespace=hidden2
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.doProcessResponseCode(HTTPConduit.java:1653)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1660)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1602)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1396)
at org.apache.cxf.ext.logging.LoggingOutputStream.postClose(LoggingOutputStream.java:53) at org.apache.cxf.io.CachedOutputStream.close(CachedOutputStream.java:228)
at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:696)
at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:63)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:307) at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:528) :307) at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:528)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:439)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:354)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:312)
at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96)
at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:140)
... 39 more
I generated the classes from the WSDL with wsdl2java (actually Quarkus does this in the dev phase).
The service has basic authentication, witch I use it in the client:
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import jakarta.enterprise.context.RequestScoped;
@RequestScoped
public class WSDLAuthentication extends Authenticator {
private String user;
private String password;
public WSDLAuthentication() {
super();
// Config properties.
this.user = "secret";
this.password = "secret";
Authenticator.setDefault(this);
}
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(this.user, this.password.toCharArray());
}
}
And before executing the service I instantiate it:
@ApplicationScoped
public class UserDataWebService {
private Config config;
private String MANDANTE;
@CXFClient("maestroProveedoresService")
private SISAPMaestroProveedoresSyncOut maestroProveedoresService;
@Inject
private ZprovsMapper zprovsMapper;
public UserDataWebService() {
// WSDL Auth.
new WSDLAuthentication();
}
public UserDataDTO getUserData(String userId) throws CustomException {
ZFIMAESTROPROV zfimaestroprov = new ZFIMAESTROPROV();
zfimaestroprov.setPMANDANTE('100');
zfimaestroprov.setPTAXNUM('123456789');
try {
// Excecute SOAP ws.
ZFIMAESTROPROVResponse zfimaestroprovResponse = maestroProveedoresService
.siSAPMaestroProveedoresSyncOut(zfimaestroprov);
Optional<String> errorOptional = Optional.ofNullable(zfimaestroprovResponse.getPERROR());
switch (errorOptional.orElse(CustomTypes.EMPTY_FIELD.getLabel())) {
case "E":
System.err.println(CustomMessagesType.USER_NOT_FOUND.getLabel());
throw new CustomException(404, CustomMessagesType.USER_NOT_FOUND.getLabel());
default:
ZPROVS userDataSAP = zfimaestroprovResponse.getSALIDA();
UserDataDTO userData = zprovsMapper.zprovsToUserDataDTO(userDataSAP);
return userData;
}
} catch (jakarta.xml.ws.WebServiceException e) {
e.printStackTrace();
throw new CustomException(503, CustomMessagesType.SERVER_UNAVAILABLE.getLabel());
}
}
}
I have also configured basic authentication in Quarkus properties (in fact, this works for getting the WSDL definition).
When I log the request, I can see the basic authentication on it:
INFO [org.apa.cxf.ser.SI_.REQ_OUT] (executor-thread-1) REQ_OUT
Address: http://mydeveloperservice/XISOAPAdapter/MessageServlet?senderParty=&senderService=hidden&receiverParty=&receiverService=&interface=SI_SAP_MaestroProveedores_sync_out&interfaceNamespace=hidden2
HttpMethod: POST
Content-Type: text/xml
ExchangeId: 1ce8c3ce-036f-4c87-b4d7-e94f2704ca73
ServiceName: SI_SAP_MaestroProveedores_sync_outService
PortName: HTTPS_Port
PortTypeName: SI_SAP_MaestroProveedores_sync_out
Headers: {Authorization=Basic supperhidden, SOAPAction="http://sap.com/xi/WebService/soap1.1", Accept=*/*}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:ZFI_MAESTRO_PROV xmlns:ns2="urn:sap-com:document:sap:rfc:functions"><P_MANDANTE>100</P_MANDANTE><P_TAXNUM>123456789</P_TAXNUM></ns2:ZFI_MAESTRO_PROV></soap:Body></soap:Envelope>
The service is under HTTP, and with wireshark I can see this traces:
In fact, in the key request, this is the trace:
Hypertext Transfer Protocol
POST /XISOAPAdapter/MessageServlet?senderParty=&senderService=hidden&receiverParty=&receiverService=&interface=SI_SAP_MaestroProveedores_sync_out&interfaceNamespace=hidden2 HTTP/1.1\r\n
[ [truncated]Expert Info (Chat/Sequence): POST /XISOAPAdapter/MessageServlet?senderParty=&senderService=hidden&receiverParty=&receiverService=&interface=SI_SAP_MaestroProveedores_sync_out&interfaceNamespace=hidden2]
[POST /XISOAPAdapter/MessageServlet?senderParty=&senderService=hidden&receiverParty=&receiverService=&interface=SI_SAP_MaestroProveedores_sync_out&interfaceNamespace=hidden2 HTTP/1.1\r\n]
[Severity level: Chat]
[Group: Sequence]
Request Method: POST
Request URI: /XISOAPAdapter/MessageServlet?senderParty=&senderService=hidden&receiverParty=&receiverService=&interface=SI_SAP_MaestroProveedores_sync_out&interfaceNamespace=hidden2
Request URI Path: /XISOAPAdapter/MessageServlet
Request URI Query: senderParty=&senderService=hidden&receiverParty=&receiverService=&interface=SI_SAP_MaestroProveedores_sync_out&interfaceNamespace=hidden2
Request URI Query Parameter: senderParty=
Request URI Query Parameter: senderService=hidden
Request URI Query Parameter: receiverParty=
Request URI Query Parameter: receiverService=
Request URI Query Parameter: interface=SI_SAP_MaestroProveedores_sync_out
Request URI Query Parameter: interfaceNamespace=hidden2
Request Version: HTTP/1.1
Connection: Upgrade, HTTP2-Settings\r\n
Content-Length: 266\r\n
[Content length: 266]
Host: mydeveloperserverr\n
HTTP2-Settings: AAEAAEAAAAIAAAABAAMAAABkAAQBAAAAAAUAAEAA\r\n
Upgrade: h2c\r\n
Accept: */*\r\n
Authorization: Basic superhidden
Content-Type: text/xml; charset=UTF-8\r\n
SOAPAction: "http://sap.com/xi/WebService/soap1.1"\r\n
User-Agent: Apache-CXF/4.0.1\r\n
\r\n
[Full request URI [truncated]: http://mydeveloperservice/XISOAPAdapter/MessageServlet?senderParty=&senderService=hidden&receiverParty=&receiverService=&interface=SI_SAP_MaestroProveedores_sync_out&interfaceNamespace=http:]
[HTTP request 1/1]
[Response in frame: 468]
File Data: 266 bytes
In witch I can identify that the client is sending the header Connection: Upgrade, HTTP2-Settings. I think that this is the problem.
Any ways I can make the request without this header?
Stacks:
- POM:
<properties> <compiler-plugin.version>3.11.0</compiler-plugin.version> <maven.compiler.release>17</maven.compiler.release> <org.mapstruct.version>1.5.5.Final</org.mapstruct.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id> <quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id> <quarkus.platform.version>3.1.1.Final</quarkus.platform.version> <skipITs>true</skipITs> <surefire-plugin.version>3.0.0</surefire-plugin.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>${quarkus.platform.group-id}</groupId> <artifactId>${quarkus.platform.artifact-id}</artifactId> <version>${quarkus.platform.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>${quarkus.platform.group-id}</groupId> <artifactId>quarkus-cxf-bom</artifactId> <version>${quarkus.platform.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>${quarkus.platform.group-id}</groupId> <artifactId>quarkus-camel-bom</artifactId> <version>${quarkus.platform.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>io.quarkiverse.cxf</groupId> <artifactId>quarkus-cxf</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-hibernate-orm</artifactId> </dependency> <dependency> <groupId>org.apache.camel.quarkus</groupId> <artifactId>camel-quarkus-cxf-soap</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-hibernate-validator</artifactId> </dependency> <dependency> <groupId>org.apache.camel.quarkus</groupId> <artifactId>camel-quarkus-soap</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-oidc</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-jdbc-oracle</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-arc</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-smallrye-health</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-hibernate-orm-panache</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy-jsonb</artifactId> </dependency> <dependency> <groupId>io.quarkiverse.cxf</groupId> <artifactId>quarkus-cxf-rt-ws-security</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-junit5</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.rest-assured</groupId> <artifactId>rest-assured</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.quarkiverse.cxf</groupId> <artifactId>quarkus-cxf-rt-features-logging</artifactId> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>${org.mapstruct.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>${org.mapstruct.version}</version> <scope>provided</scope> </dependency> </dependencies> - SAP PI/PO 7.5
Note: I did some search in SAP, and the only thing that I found was this note.
Sorry for the long post.
Thanks.
I tried to search how to disable Connection: Upgrade, HTTP2-Settings in Apache CXF, but coudn't find anything.

The main problem is that SAP PO has a bug (reported in the note in the question above). The request is via HTTP 1.1 with the upgrade protocol, and SAP PO is the one that should interpret (accept or dismiss the header) this request, which in this case is not happening and sending a 403 error.
So, a workaround is sending the request via HTTP 1.1 without the upgrade header. Implementing this configuration in a class achieves that:
This configures the CFX client to use HTTP 1.1 and not try to upgrade to HTTP/2 protocol.
For more information check this sources: Quarkus Github issues, CXF issues.