Soap Fault Message Resolver isn't invoked after adding Wss4jSecurityInterceptor config - spring

I have written a web service client (using Java Spring and JAXB Marshaller) that works with a 3rd party web service. When I send a valid request everything works well. When I send an invalid request then the web service server responds with a SOAP Fault. The client application just fails with a UnmarshallingFailureException
org.springframework.oxm.UnmarshallingFailureException: JAXB unmarshalling
exception; nested exception is javax.xml.bind.UnmarshalException:
unexpected element (uri:"http://schemas.xmlsoap.org/soap/envelope/", local:"Fault").
Appears to me that my ws client isn't able to decipher the SOAP fault returned by the web service. I wrote a custom FaultMessageResolver, but it doesn't get invoked (I set a breakpoint there but it doesn't hit. The FaultMessageResolver just worked fine before I added the Wss4jSecurityInterceptor for signature, encryption/decryption stuff). Here's the code:
public class VehicleServiceClientExceptionResolver implements FaultMessageResolver {
#Override
public void resolveFault(WebServiceMessage message) throws IOException {
SoapMessage soapMessage = (SoapMessage) message;
try {
JAXBContext context = JAXBContext.newInstance(ErrorMessages.class);
Unmarshaller unMarshaller = context.createUnmarshaller();
ErrorMessages errorMessages = (ErrorMessages)unMarshaller.unmarshal(soapMessage.getSoapBody().getFault().getFaultDetail().getDetailEntries().next().getSource());
if (errorMessages.getErrorMessage().size() > 0) {
throw new VehicleServiceClientException(errorMessages);
}
} catch (JAXBException e) {
LOGGER.debug(e.getMessage());
}
}
}
And this custom soap fault resolver is injected into client side web service template like below:
<bean id="vehicleQuotationWebServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory"/>
<property name="interceptors">
<list>
<ref bean="wsSecurityInterceptor"/>
</list>
</property>
<property name="marshaller" ref="vehicleQuotationMarshaller" />
<property name="unmarshaller" ref="vehicleQuotationMarshaller" />
<property name="messageSender" ref="urlMessageSender"/>
<property name="faultMessageResolver" ref="vehicleServiceClientFaultMessageResolver" />
<property name="defaultUri" value="https://*********/*********Service"/>
</bean>
The most weird thing is although I got that unmarshall exception, I did see the encrypted server response was decrypted in my eclipse console when I change the log level from INFO to DEBUG, I am not sure where this DigesterOutputStream comes from, but I think it might be the key to solve this.
Anyone got any idea? Thanks!
DEBUG p.xml.dsig.internal.DigesterOutputStream:
<soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Id-af090516-9e00-4590-b481-c78e59d6b2fc"><soapenv:Fault><faultcode>soapenv:Client.Validation</faultcode><faultstring</faultstring><detail><em:ErrorMessages xmlns:em="urn:ford/errormessage/v1.0"><em:ErrorMessage><em:ErrorCode>GLSE903100</em:ErrorCode><em:ErrorDescription> CTT System Quote Id already exists ('1041')</em:ErrorDescription><em:ErrorTime>2014-05-16T15:13:20</em:ErrorTime></em:ErrorMessage></em:ErrorMessages></detail></soapenv:Fault></soapenv:Body>

I found the solution here: Adding a WebServiceMessageExtractor<Object> to:
WebServiceTemplate.sendAndReceive(
new WebServiceMessageCallback(),
new WebServiceMessageExtractor<Object>())
does the trick.

Another solution:
public class ExampleInterceptor implements ClientInterceptor {
public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {
var resp = (SoapMessage) messageContext.getResponse();
Optional.of(resp)
.filter(res -> !hasFault(res))
.orElseThrow(() -> new SoapFaultClientException(resp));
return true;
}
private boolean hasFault(final WebServiceMessage response) {
return Optional.ofNullable(response)
.filter(resp -> resp instanceof FaultAwareWebServiceMessage)
.map(resp -> (FaultAwareWebServiceMessage) resp)
.map(FaultAwareWebServiceMessage::hasFault)
.orElse(false);
}
}
#Configuration
public class ExampleConnectorConfig extends WSConnectorConfig
#Bean
public WSConnector soapConnector(Jaxb2Marshaller marshaller) {
var client = new WSConnector(messageFactory());
client.setInterceptors(new ClientInterceptor[]{new ExampleInterceptor()});
client.setDefaultUri(proxy);
return client;
}
//Example
#Bean
public SaajSoapMessageFactory messageFactory() {
SaajSoapMessageFactory messageFactory = new SaajSoapMessageFactory();
messageFactory.afterPropertiesSet();
return messageFactory;
}
}

Related

Spring Integration AOP for Logging outbound Http requests

I was looking at a post from 2014 about using Spring AOP for logging HTTP requests/replies:
Spring integration + logging response time for http adapters(or any endpoint)
To this end, I tried this AOP configuration:
<aop:config >
<aop:aspect id="myAspect" ref="inboundOutboundHttpLogging">
<aop:pointcut id="handleRequestMessageMethod"
expression="execution(* org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleRequestMessage(*))
and
args(message))" />
<aop:before method="requestMessageSent" pointcut-ref="handleRequestMessageMethod" arg-names="message"/>
</aop:aspect>
</aop:config>
Is there perhaps a newer way of using AOP for logging HTTP requests? I want to avoid having to put per-request logging (i.e. outbound-gateway advice on each gateway).
Thanks for any pointers.
The handleRequestMessage() is essentially an input message to this gateway and output. So, if you don't like implementing an AbstractRequestHandlerAdvice and adding it into each your gateway via their <request-handler-advice-chain>, then consider to use a <wire-tap> for input and output channels of those gateway.
You may implement, though, a BeanPostProcessor.postProcessBeforeInitialization() to add your custom AbstractRequestHandlerAdvice into those HTTP gateways you are interested in.
My point is that <aop:aspect> you are presenting us really might lead to some unexpected behavior, like that final method concern you have edit out from your question...
Based upon the suggestions made by #artem-bilan, I was able to find a solution similar to AOP for injecting logging AbstractRequestHandlerAdvice into HTTP outbound request processing. I'm contributing this as a way of showing a possible solution for anyone else who comes across this question.
As #artem-bilan mentions, there is a mechanism for injecting AbstractRequestHandlerAdvice into a AbstractReplyProducingMessageHandler such as an HttpRequestExecutingMessageHandler. In my case, I'm wanting to log the message contents (header and payload) prior to the HTTP call and also log the return message (header and payload). This works nicely.
#artem-bilan suggests that the BeanPostProcessor mechanism can allow to inject the advice without having to add that declaration to each http outbound bean. The BeanPostProcessor looks like this:
public class AddHttpOutboundAdvicePostProcessor implements BeanPostProcessor {
final List<Advice> adviceList;
final AddHttpOutboundAdvicePostProcessor(List<Advice> adviceList) {
this.adviceList = adviceList;
}
#Override
public Object postProcessAfterInitialization(#NonNull Object bean,
#NonNull String beanName)
throws BeansException {
if (bean instanceof AbstractHttpRequestExecutingMessageHandler) {
((AbstractHttpRequestExecutingMessageHandler) bean).setAdviceChain(adviceList);
}
return bean;
}
}
We need to set up this bean into our context. (I'm a die-hard declarative fan hence this is in XML.)
<bean id = "addHttpLoggingPostProcessor"
class = "com.my.package.AddHttpOutboundAdvicePostProcessor" >
<constructor-arg name="adviceList>
<util:list>
<ref bean="outboundLogger" />
</util:list>
</constructor-arg>
</bean>
Here, the outboundLogger is a bean that managers the request-handler-advice. In my choice of implementation, I'm sending a copy of the outbound message to a channel for logging beforehand, and a copy of the response message down another channel for logging the response. The XML declaration of the bean takes the two channel names as constructors:
<bean id="outboundLogger" class="com.my.package.HttpRequestProcessorLogger" >
<constructor-arg name="requestLoggingChannelName" value="XXX" />
<constructor-arg name="responseLoggingChannelName" value="YYY" />
</bean>
where XXX and YYY are the names of channels to the components that perform the logging. I've set these channels to be ExecutorChannels so that the logging is performed asynchronously.
The HttpRequestProcessorLogger bean manages the call to handleRequestMessage():
public class HttpRequestProcessorLogger extends AbstractRequestHandlerAdvice {
private MessageChannel requestLoggingChannel;
private MessageChannel responseLoggingChannel;
private String requestLoggingChannelName;
private String responseLoggingChannelName;
private BeanFactory beanFactory;
public HttpRequestProcessorLogger(String requestLoggingChannelName, String responseLoggingChannelName) {
this.requestLoggingChannelName = requestLoggingChannelName;
this.responseLoggingChannelName = responseLoggingChannelName;
}
#Override
protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message) {
getChannels();
requestLoggingChannel.send(message);
final Object result = callback.execute();
final message<?> outputMessage =
(MessageBuilder.class.isInstance(result) ? ((MessageBuilder<?>) result).build()
: (Message<?>) result;
responseLoggingChannel.send(outputMessage);
return outputMessage;
}
private synchronized void getChannels() {
if (requestLoggingChannelName != null) {
final DestinationResolver<MessageChannel>
channelResolver = ChannelResolverUtils.getChannelResolver(this.beanFactory);
requestLoggingChannel = channelResolver.resolverDestination(requestLoggingChannelName);
responseLoggingChannel = channelResolver.resolverDestination(responseLoggingChannelName);
requestLoggingChannelName = null;
responseLoggingChannelName = null;
}
}
#Override
public void setBeanFactory(#NonNull BeanFactory beanFactory) throws BeanException {
this.beanFactory = beanFactory;
}
}

Spring transaction closes connection once commit for Propagation type REQUIRED_NEW

In my application i am processing messages from queue using camel and process it in multiple threads.
I tried to persist the data to a table during the process with PlatformTransactionManager, with Propagation type "REQUIRED_NEW", but on using the commit the transaction seems to be closed. and connection not available for other process.
The application context.xml looks as in below snippet.
<!-- other definitions -->
<context:property-placeholder location="classpath:app.properties"/>
<bean id="appDataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="${dburl}"/>
<property name="username" value="${dbUserName}"/>
<property name="password" value="${dbPassword}"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="appDataSource" />
</bean>
<!-- Other bean reference. -->
<bean id="itemDao" class="app.item.dao.ItemDao">
<property name="dataSource" ref="appDataSource"/>
</bean>
<bean id="orderProcess" class="app.order.process.OrderProcess" scope="prototype">
<property name="itemDao" ref="itemDao"/>
</bean>
I have a DAO classes something like below, also there are other Dao's.
public class ItemDao{
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private PlatformTransactionManager transactionManager;
private TransactionStatus transactionStatus;
//Setter injection of datasource
public void setDataSource(DataSource dataSource) {
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
this.transactionManager = new DataSourceTransactionManager(dataSource);
}
//setterInjection
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public void createAndStartTransaction()
{
DefaultTransactionDefinition transDef = new DefaultTransactionDefinition();
transDef.setPropagationBehavior(Propagation.REQUIRES_NEW.ordinal());
if (transactionManager != null)
{
transactionStatus = transactionManager.getTransaction(transDef);
} // if transactionManager null log something went incorrect
}
public void commit() throws Exception
{
if (transactionManager != null && transactionStatus != null)
{
transactionManager.commit(transactionStatus);
}
}
public void rollBack() throws Exception
{
if (transactionManager != null && transactionStatus != null)
{
transactionManager.rollback(transactionStatus);
}
}
}
Finally in the code flow, once the context is defined and using those beans process the message.
Parse the message from a queue
validate the message, check if the metadata information in database, insert the data to the database.
I am trying to persist the data to database immediately at this time
After that the flow will be processing further.
The challange is that when we tried to use the
Below is what I did to persist the data to database. Refer the code snippet.
But this is working when i perform a a testing with single instance.
//....
//.. fetch info from data base using other dao's
//.. insert into another table
// Below code i added where i need to persist the data to database
try{
orderProcess.itemDao.createAndStartTransaction();
orderProcess.itemDao.
}catch(Exception exe){
orderProcess.itemDao.rollBack();
}finally{
//within try catch
orderProcess.commit();
}
//.. other dao's used to fetch the data from different table database
//.. still the process is not completed
When the process try to fetch the next message from queue, it was not able to get the connection and throws connection null exception.
What is observed is the process closes the connection abruptly, so when the process picks the next message it is not having connection defined.
SQL state [null]; error code [0]; Connection is null.; nested exception is java.sql.SQLException: Connection is null.
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:84)
Any idea how to persist the transaction independently during the process.
The design is not maintainable, but was able to modify the code for my requirement. Didn't notice any side effect
The DAO call was done from different layer.
I extracted the insert/update/delete to Specific DAO class.
And created a sperate method to call the insert(), etc. in this DAO.
public void checkAndValidate(Object input){
// check data exsits in DB
boolean exists = readDao.checkForData(input);
if(!exists){
// the method which was annotated with transactional
insertDataToDB(input);
}
//.. other process..
}
#Transactional
public Object insertDataToDB(Object data) throws exception {
try{
writeDao.insertData(data);
} catch(Exception exe)
{
//handle exception
}
}

Spring-WS - return valid response on Exception

I have soap andpoint which should return response type A based on request type B. But during processing of request, i'm expecting errors (like unable to call downastream service) which throw cutom exception for example type ExpEx. And now i wat to do custom error mapping, because in case of errors I don't want to return type A but want to return type CFault (which is defined in wsd also).
Now question:
- is is possible to create custom eero handle which rturn CFault instead A
- or is it possible to make enpoint allow to return two types of response A and CFault (I think Object) ?
my enpoint:
public class FantasticEndpoint extend WebServiceEndpoint {
private static final String NAMESPACE = "http://www.fantastic.com/SOA/tmp/FantasticService/v_2_4";
#PayloadRoot(namespace = NAMESPACE, localPart = "handleBOperation")
#ResponsePayload
public A createConsumers(#RequestPayload B b{
//do some dangerous logic possility throw EXCEPTION
// if EXCEPTION return CFault or return A if normal processing
}
}
First of all, take a look on that: https://docs.spring.io/spring-ws/sites/2.0/reference/html/server.html#server-endpoint-exception-resolver
I am going to highlight some of that:
According to documentation, you can create your own exception class to indicate the SOAP Fault that should be returned whenever that exception is thrown. Just annotate class with #SoapFault annotation.
import org.springframework.ws.soap.server.endpoint.annotation.FaultCode;
import org.springframework.ws.soap.server.endpoint.annotation.SoapFault;
#SoapFault(faultCode = FaultCode.SERVER)
public class MyCustomException extends Exception {
public MyClientException(String message) {
super(message);
}
}
If this doesn't suit you, you can mess with SoapFaultAnnotationExceptionResolver (https://docs.spring.io/spring-ws/site/apidocs/org/springframework/ws/soap/server/endpoint/SoapFaultAnnotationExceptionResolver.html). This resolver lets you map exception classes to SOAP Fault:
<beans>
<bean id="exceptionResolver" class="org.springframework.ws.soap.server.endpoint.SoapFaultMappingExceptionResolver">
<property name="defaultFault" value="SERVER"/>
<property name="exceptionMappings">
<value>
org.springframework.oxm.ValidationFailureException=CLIENT,Invalid request
</value>
</property>
</bean>
You can use this to add SoapFaultDetail:
public class MySoapFaultDefinitionExceptionResolver extends SoapFaultMappingExceptionResolver {
private static final QName CODE = new QName("code");
private static final QName DESCRIPTION = new QName("description");
#Override
protected void customizeFault(Object endpoint, Exception ex, SoapFault fault) {
if (ex instanceof MyCustomException) {
SoapFaultDetail detail = fault.addFaultDetail();
detail.addFaultDetailElement(CODE).addText("SOMECODE");
detail.addFaultDetailElement(DESCRIPTION).addText(ex.getMessage());
}
}
I have once used EndpointInterceptor to mess with SOAPHeader. Perhaps you can use it to do the work with SOAPFault (https://docs.spring.io/spring-ws/site/apidocs/org/springframework/ws/server/EndpointInterceptor.html).
You can extract SOAPFault from MessageContext like this:
#Override
public boolean handleFault(MessageContext messageContext, Object o) throws Exception {
SaajSoapMessage soapResponse = (SaajSoapMessage) messageContext.getResponse();
SOAPMessage soapMessage = soapResponse.getSaajMessage();
SOAPBody body = soapMessage.getSOAPBody();
SOAPFault fault = body.getFault();
//do something with fault here
return true
}
You can read about SOAPFault interface here https://docs.spring.io/spring-ws/site/apidocs/org/springframework/ws/soap/SoapFault.html

Spring Security: How to get the originally thrown exception of a failed XwsSecurityInterceptor.validateMessage call

My application is using Spring Security to validate incoming Endpoint calls. I am trying to give the client specific error codes when anything goes wrong within the XwsSecurityInterceptor but I haven't yet found a way to do this.
This is what I have tried: I am using an EndpointInterceptor that inherits from XwsSecurityInterceptor:
<bean name="myInterceptor" id="myInterceptor" class="x.y.MyPreAuthenticationSecurityInterceptor">
<property name="policyConfiguration" value="classpath:/security.xml" />
<property name="callbackHandlers">
<list>
<bean id="myCallbackHandler" class="x.y.MyCallbackHandler" />
</list>
</property>
</bean>
The interceptor has a CallbackHandler 'myCallbackHandler' that handles PasswordValidationCallbacks. For testing purposes for each callback it attaches a validator that will instantly throw a certain exception (CustomException) with a certain error code:
#Override
protected void handleInternal(Callback callback) throws IOException, UnsupportedCallbackException {
if (callback instanceof PasswordValidationCallback) {
PasswordValidationCallback validationCallback = (PasswordValidationCallback) callback;
if (validationCallback.getRequest() instanceof PasswordValidationCallback.PlainTextPasswordRequest) {
validationCallback.setValidator(new MyValidator());
return;
}
} else if (callback instanceof CleanupCallback) {
SecurityContextHolder.clearContext();
return;
}
throw new UnsupportedCallbackException(callback);
}
private class MyValidator implements PasswordValidationCallback.PasswordValidator {
public boolean validate(PasswordValidationCallback.Request request) throws PasswordValidationCallback.PasswordValidationException
{
throw new PasswordValidationCallback.PasswordValidationException("test", new CustomException("some error code"));
}
}
As specified in https://docs.spring.io/spring-ws/site/reference/html/security.html, section 7.2.5 the exception handling is done in the handleValidationException method.
In 'MyPreAuthenticationSecurityInterceptor' I am overriding the handleValidationException method:
#Override
public boolean handleValidationException(WsSecurityValidationException ex, MessageContext messageContext) {
if (logger.isWarnEnabled()) {
logger.warn("Could not validate request: " + ex.getMessage());
}
return false;
}
Problem is that when debugging I can't find my CustomException in WsSecurityValidationException. The root cause of is 'com.sun.xml.wss.XWSSecurityException: Invalid Username Password Pair'.
Am I going about this the wrong way?

Spring: import a module with specified environment

Is there anything that can achieve the equivalent of the below:
<import resource="a.xml">
<prop name="key" value="a"/>
</import>
<import resource="a.xml">
<prop name="key" value="b"/>
</import>
Such that the beans defined in resouce a would see the property key with two different values? The intention would be that this would be used to name the beans in the imports such that resource a.xml would appear:
<bean id="${key}"/>
And hence the application would have two beans named a and b now available with the same definition but as distinct instances. I know about prototype scope; it is not intended for this reason, there will be many objects created with interdepednencies that are not actually prototypes. Currently I am simply copying a.xml, creating b.xml and renaming all the beans using the equivalent of a sed command. I feel there must be a better way.
I suppose that PropertyPlaceholderConfigurers work on a per container basis, so you can't achieve this with xml imports.
Re The application would have two beans named a and b now available with the same definition but as distinct instances
I think you should consider creating additional application contexts(ClassPathXmlApplicationContext for example) manually, using your current application context as the parent application context.
So your many objects created with interdependencies sets will reside in its own container each.
However, in this case you will not be able to reference b-beans from a-container.
update you can postprocess the bean definitions(add new ones) manually by registering a BeanDefinitionRegistryPostProcessor specialized bean, but this solution also does not seem to be easy.
OK, here's my rough attempt to import xml file manually:
disclaimer: I'm very bad java io programmer actually so double check the resource related code :-)
public class CustomXmlImporter implements BeanDefinitionRegistryPostProcessor {
#Override
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
private Map<String, String> properties;
public void setProperties(Map<String, String> properties) {
this.properties = properties;
}
public Map<String, String> getProperties() {
return properties;
}
private void readXml(XmlBeanDefinitionReader reader) {
InputStream inputStream;
try {
inputStream = new ClassPathResource(this.classpathXmlLocation).getInputStream();
} catch (IOException e1) {
throw new AssertionError();
}
try {
Scanner sc = new Scanner(inputStream);
try {
sc.useDelimiter("\\A");
if (!sc.hasNext())
throw new AssertionError();
String entireXml = sc.next();
PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper("${",
"}", null, false);
Properties props = new Properties();
props.putAll(this.properties);
String newXml = helper.replacePlaceholders(entireXml, props);
reader.loadBeanDefinitions(new ByteArrayResource(newXml.getBytes()));
} finally {
sc.close();
}
} finally {
try {
inputStream.close();
} catch (IOException e) {
throw new AssertionError();
}
}
}
private String classpathXmlLocation;
public void setClassPathXmlLocation(String classpathXmlLocation) {
this.classpathXmlLocation = classpathXmlLocation;
}
public String getClassPathXmlLocation() {
return this.classpathXmlLocation;
}
#Override
public void postProcessBeanDefinitionRegistry(
BeanDefinitionRegistry registry) throws BeansException {
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
readXml(reader);
}
}
XML configuration:
<bean class="CustomXmlImporter">
<property name="classPathXmlLocation" value="a.xml" />
<property name="properties">
<map>
<entry key="key" value="a" />
</map>
</property>
</bean>
<bean class="CustomXmlImporter">
<property name="classPathXmlLocation" value="a.xml" />
<property name="properties">
<map>
<entry key="key" value="b" />
</map>
</property>
</bean>
this code loads the resources from classpath. I would think twice before doing something like that, anyway, you can use this as a starting point.

Resources