Reputation: 21
I tried to connect to TERYT but I get an error about the lack of authorization. WSDL address - https://uslugaterytws1test.stat.gov.pl/wsdl/terytws1.wsdl
java.lang.IllegalStateException: Failed to execute ApplicationRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:765) [spring-boot-2.7.1.jar:2.7.1]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:752) [spring-boot-2.7.1.jar:2.7.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) [spring-boot-2.7.1.jar:2.7.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) [spring-boot-2.7.1.jar:2.7.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) [spring-boot-2.7.1.jar:2.7.1]
at com.example.teryt.TerytApplication.main(TerytApplication.java:15) [classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_332]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_332]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_332]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_332]
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-2.7.1.jar:2.7.1]
Caused by: com.sun.xml.internal.ws.fault.ServerSOAPFaultException: Client received SOAP Fault from server: An error occurred when processing the security tokens in the message. Please see the server log to find more detail regarding exact cause of the failure. at com.sun.xml.internal.ws.fault.SOAP11Fault.getProtocolException(SOAP11Fault.java:178) ~[na:1.8.0_332] at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:116) ~[na:1.8.0_332] at com.sun.xml.internal.ws.client.sei.StubHandler.readResponse(StubHandler.java:238) ~[na:1.8.0_332] at com.sun.xml.internal.ws.db.DatabindingImpl.deserializeResponse(DatabindingImpl.java:189) ~[na:1.8.0_332] at com.sun.xml.internal.ws.db.DatabindingImpl.deserializeResponse(DatabindingImpl.java:276) ~[na:1.8.0_332] at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:104) ~[na:1.8.0_332] at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:77) ~[na:1.8.0_332] at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:147) ~[na:1.8.0_332] at com.sun.proxy.$Proxy83.pobierzListeWojewodztw(Unknown Source) ~[na:na] at com.example.teryt.TerytClient.getResponse(TerytClient.java:31) ~[classes/:na] at com.example.teryt.TerytApplication.lambda$lookup$0(TerytApplication.java:20) [classes/:na] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:762) [spring-boot-2.7.1.jar:2.7.1]
This is what the correct query should look like:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://tempuri.org/"> soapenv: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"> <wsse:UsernameToken wsu:Id="UsernameToken-2018-01-11T00:16:02+00:00"> wsse:UsernameTestPubliczny</wsse:Username> wsse:Password1234abcd</wsse:Password> </wsse:UsernameToken> </wsse:Security> <wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://tempuri.org/ITerytWs1/PobierzListeWojewodztw</wsa:Action> </soapenv:Header> soapenv:Body ns1:PobierzListeWojewodztw ns1:DataStanu2020-05-18</ns1:DataStanu> </ns1:PobierzListeWojewodztw> </soapenv:Body> </soapenv:Envelope>
TerytApplication.java:
@SpringBootApplication
public class TerytApplication {
public static void main(String[] args) {
SpringApplication.run(TerytApplication.class, args);
}
@Bean
ApplicationRunner lookup(TerytClient terytClient){
return args -> System.out.println(terytClient.getResponse());
}
}
Client.java:
@Component
public class TerytClient extends WebServiceGatewaySupport {
public Boolean getResponse() throws DatatypeConfigurationException {
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(new Date());
XMLGregorianCalendar xCal = DatatypeFactory.newInstance()
.newXMLGregorianCalendar(cal);
ITerytWs1 instance = new TerytWs1().getCustom(new AddressingFeature(true));
Binding binding = ((BindingProvider) instance).getBinding();
List<Handler> handlerList = binding.getHandlerChain();
if (handlerList == null)
handlerList = new ArrayList<Handler>();
handlerList.add(new TerytHeaderHandler("TestPubliczny", "1234abcd"));
binding.setHandlerChain(handlerList);
System.out.println(instance.pobierzListeWojewodztw(xCal));
return instance.czyZalogowany();
}
HeaderHandler.java
@Override
public boolean handleMessage(SOAPMessageContext smc) {
Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outboundProperty.booleanValue()) {
try {
SOAPEnvelope envelope = smc.getMessage().getSOAPPart().getEnvelope();
SOAPHeader header = envelope.getHeader();
SOAPElement security = header.addChildElement("Security", "wsse",
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
SOAPElement usernameToken = security.addChildElement("UsernameToken", "wsse");
SOAPElement username = usernameToken.addChildElement("Username", "wsse");
username.addTextNode(wsUser);
SOAPElement password = usernameToken.addChildElement("Password", "wsse");
password.setAttribute("Type",
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
password.addTextNode(wsPassword);
} catch (Exception e) {
e.printStackTrace();
}
} else {
//This handler does nothing with the response from the Web Service
//even though it should probably check its mustUnderstand headers
SOAPMessage message = smc.getMessage();
}
return outboundProperty;
}
@Override
public boolean handleFault(SOAPMessageContext context) {
// TODO Auto-generated method stub
return false;
}
@Override
public void close(MessageContext context) {
// TODO Auto-generated method stub
}
// Gets the header blocks that can be processed by this Handler instance.
@Override
public Set<QName> getHeaders() {
QName securityHeader = new QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
"Security");
HashSet<QName> headers = new HashSet<QName>();
headers.add(securityHeader);
return headers;
}
}
I would be grateful for any help and suggestions.
Upvotes: 2
Views: 1623
Reputation: 370
When building the WS-Security headers, I recommend you to use Apache WSS4J. I am attaching a code example that I use frequently.
import lombok.extern.slf4j.Slf4j;
import org.apache.wss4j.dom.WSConstants;
import org.apache.wss4j.dom.message.WSSecHeader;
import org.apache.wss4j.dom.message.WSSecTimestamp;
import org.apache.wss4j.dom.message.WSSecUsernameToken;
import org.w3c.dom.Element;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
@Slf4j
public class ClientWSSecurityUsernameTokenHandler implements
SOAPHandler<SOAPMessageContext> {
public ClientWSSecurityUsernameTokenHandler(
String userName, String password) {
_userName = userName;
_password = password;
}
@Override
public Set<QName> getHeaders() {
final String NAMESPACE_URI =
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
final String LOCAL_PART = "Security";
final String PREFIX = "wsse";
final QName wsSecurity = new QName(NAMESPACE_URI, LOCAL_PART, PREFIX);
final Set<QName> headers = new HashSet<QName>();
headers.add(wsSecurity);
return headers;
}
@Override
public boolean handleMessage(SOAPMessageContext soapMessageContext) {
Boolean outboundProperty = (Boolean) soapMessageContext.get(
MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outboundProperty) {
try {
SOAPMessage soapMessage = soapMessageContext.getMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
SOAPHeader soapHeader = soapMessage.getSOAPHeader();
if (null == soapHeader) {
SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
soapHeader = soapEnvelope.addHeader();
}
WSSecHeader wsSecHeader = new WSSecHeader(soapPart);
Element securityElement =
wsSecHeader.insertSecurityHeader();
_addUsernamePassword(soapMessageContext, soapPart, wsSecHeader);
WSSecTimestamp wsSecTimeStamp = new WSSecTimestamp(wsSecHeader);
wsSecTimeStamp.build();
_appendSecurityHeader(soapHeader, securityElement);
_logSOAPMessage(soapMessageContext.getMessage());
}
catch (Exception exception) {
log.error(exception.getMessage(), exception);
}
}
return true;
}
private String getPassword() {
return _password;
}
private String getUserName() {
return _userName;
}
@Override
public boolean handleFault(SOAPMessageContext soapMessageContext) {
_logSOAPMessage(soapMessageContext.getMessage());
return true;
}
@Override
public void close(MessageContext messageContext) {
}
private String _userName;
private String _password;
private void _appendSecurityHeader(
SOAPHeader soapHeader, Element securityElement) {
soapHeader.removeChild(securityElement);
soapHeader.appendChild(securityElement);
}
private void _addUsernamePassword(
SOAPMessageContext soapMessageContext, SOAPPart soapPart,
WSSecHeader wsSecHeader) {
log.debug("Adding Username Token for the user: {}", getUserName());
WSSecUsernameToken usernameToken = new WSSecUsernameToken(wsSecHeader);
usernameToken.setUserInfo(getUserName(), getPassword());
usernameToken.setPasswordType(WSConstants.PASSWORD_TEXT);
usernameToken.addCreated();
usernameToken.addNonce();
usernameToken.build();
}
private void _logSOAPMessage(SOAPMessage message) {
if (log.isDebugEnabled()) {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
try {
message.writeTo(bout);
String msg = bout.toString("UTF-8");
log.debug("Start of SOAP Message");
log.debug(msg);
log.debug("End of SOAP Message");
}
catch (SOAPException | IOException exception) {
if (log.isErrorEnabled()) {
log.error(exception.getMessage(), exception);
}
}
}
}
}
Source Code 1 - SOAP Handler ClientWSSecurityUsernameTokenHandler
The following code instead shows how to add the handler to the chain.
ClientWSSecurityUsernameTokenHandler
clientWSSSecurityUsernameTokenHandler =
new ClientWSSecurityUsernameTokenHandler(soapClientProperties.getUsername(),
soapClientProperties.getPassword());
List<Handler> handlerChain = List.of(clientWSSSecurityUsernameTokenHandler);
((BindingProvider) serviceSOAP).getBinding().setHandlerChain(handlerChain);
Source Code 2 - Add the ClientWSSecurityUsernameTokenHandler to SOAP Handler Chain
The following code instead shows how to add the wss4j-ws-security-dom as dependency.
<dependency>
<groupId>org.apache.wss4j</groupId>
<artifactId>wss4j-ws-security-dom</artifactId>
<version>2.4.1</version>
</dependency>
Upvotes: 1