I am working a web service using Spring WS. I get the...
WSS0258: More Receiver requirements specified than present in the message
...for a Consumer call as shown below with a X509 Certificate (issued from a central system Desmon).
I do not have much experience working with WS-Security. Therefore need some help to set my security policy file and further hints.
I would really appreciate any hints/help.
Consumer Call
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://app.sample.com/customermanagement/btc/service" xmlns:acc="http://app.sample.com/customermanagement/btc/schema/accountslinkingobject">
<soapenv:Header xmlns:header="http://com.sample.app.japi">
<header:ApplicationID>XX</header:ApplicationID>
<header:CallID>XX1</header:CallID>
<wsse:Security soapenv:actor="http://schemas.xmlsoap.org/soap/actor/next" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="DESMONCertificate" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">REMOVED MORA THAN 2000 BYTES OF CERTIFICATE CONTENT</wsse:BinarySecurityToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>.......</soapenv:Body>
</soapenv:Envelope>
And this is my security policy file and interceptors:
Security File
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config" dumpMessages="true">
<xwss:RequireSignature requireTimestamp="false">
<xwss:X509Token keyReferenceType="Direct" />
</xwss:RequireSignature>
</xwss:SecurityConfiguration>
Java code from Spring Configuration file
#Bean
public XwsSecurityInterceptor securityInterceptor() {
XwsSecurityInterceptor result = new XwsSecurityInterceptor();
result.setCallbackHandler(callbackHandler());
result.setPolicyConfiguration(new ClassPathResource("security-policy.xml"));
return result;
}
#Bean SpringCertificateValidationCallbackHandler callbackHandler() {
SpringCertificateValidationCallbackHandler handler = new SpringCertificateValidationCallbackHandler();
handler.setAuthenticationManager(authenticationManager());
return handler;
}
#Bean
public ProviderManager authenticationManager() {
ProviderManager pm = new ProviderManager(providers());
return pm;
}
#Bean
public List<AuthenticationProvider> providers() {
X509AuthenticationProvider provider = new X509AuthenticationProvider();
provider.setX509AuthoritiesPopulator(new X509AuthoritiesPopulator() {
#Override
public UserDetails getUserDetails(X509Certificate cert) throws AuthenticationException {
log.info("Got a Certificate: "+cert.toString());
return null;
}
});
List<AuthenticationProvider> list = new ArrayList<AuthenticationProvider>();
list.add(provider);
return list;
}
Thanks a lot in advance!
Related
Hi I am developing XML Soap services using WCF. My requirement is to update some database table. I have one method to update values in the db. Below is my service.
[ServiceContract]
public interface IOpportunity
{
[OperationContract]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Xml, UriTemplate = "postmethod/updateOpportunity")]
bool updateOpportunity(opportunityActivity obj);
}
[DataContract]
public class opportunityActivity
{
[DataMember]
public string opportunityID { get; set; }
[DataMember]
public string opportunityStatus { get; set; }
[DataMember]
public string opportunityserviceType { get; set; }
}
Below is my xml.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:s="http://localhost:39512/Opportunity.svc">
<soapenv:Header/>
<soapenv:Body>
<s:request>
<opportunityID>1-1D5SJX</opportunityID>
<opportunityStatus>Completed</opportunityStatus>
<opportunityserviceType>LEASE_REQUEST</opportunityserviceType>
</s:request>
</soapenv:Body>
</soapenv:Envelope>
when i i try as shown above i get 400 bad request error.May i know am i following correct approach to test the service? Can someone correct me if i am doing wrong? Any help would be greatly appreciated. Thank you.
You have to pass a soap message to the service endpoint.
Eg
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:s="http://myNamespace/">
<soapenv:Header/>
<soapenv:Body>
<s:request>
....
</s:request>
</soapenv:Body>
</soapenv:Envelope>
To get hold of a soap message you should use the service endpoint definition and use some tooling to generate a valid request.
Additionally, you should not be sending data to the endpoint address with ?wsdl as part of the address. It should only be the endpoint address.
I am really bugged with an unmarshalling issue with the response from the SOAP service. I am using springboot application and WebServiceTemplate for calling an existing SOAP service. I am using below code to set up beans for marshalling and webservicetemplate. Any help is highly appreciated.
On calling webServiceTemplate.marshalSendAndReceive(request); I am expecting TravelResponse object but it is giving me JAXBElement<TravelResponse> object as response. I need help to understand
1) why is it giving above response instead of TravelResponse
2) How to convert to TravelResponse
Code snippet below:
#Bean
Jaxb2Marshaller jaxb2Marshaller() {
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
jaxb2Marshaller.setContextPath("com.cater.trip.simple_api.trip.v1");
return jaxb2Marshaller;
}
#Bean
public WebServiceTemplate webServiceTemplate() throws Exception {
WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
webServiceTemplate.setMessageFactory(getMessageFactory());
webServiceTemplate.setMarshaller(jaxb2Marshaller());
webServiceTemplate.setUnmarshaller(jaxb2Marshaller());
webServiceTemplate.setDefaultUri(defaultUri);
webServiceTemplate.setMessageSender(getMessageSender());
return webServiceTemplate;
}
#Bean
public SaajSoapMessageFactory getMessageFactory() {
return new SaajSoapMessageFactory();
}
#Bean
public HttpComponentsMessageSender getMessageSender() {
return new HttpComponentsMessageSender();
}
#Override
public Object getData( ) {
ObjectFactory clientFac = new ObjectFactory();
TravelRequest request = populateRequest(clientFac);
TravelResponse res = (TravelResponse) webServiceTemplate.marshalSendAndReceive(request);
return res;
}
As per Spring's doc, WebServiceTemplate.marshalSendAndReceive(Object requestPayload)
Sends a web service message that contains the given payload, marshalled by the configured Marshaller. Returns the unmarshalled payload of the response message, if any.
This will only work with a default uri specified!
So, you can do this to return the expected response.
JAXBElement<TravelResponse> res = (JAXBElement<TravelResponse>) webServiceTemplate.marshalSendAndReceive(request);
return res.getValue();
Try JaxbIntrospector.getValue to get the actual response from JAXB element.
TravelResponse response = JaxbIntrospector.getValue(jaxbElement);
I'm working on custom axis2 module for wso2 esb. Right now I'm using code from https://docs.wso2.com/display/ESB490/Writing+an+Axis2+Module
and I have a problem with incoming requests. It doesn't matter what request I send because it always looks like this:
<?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body/></soapenv:Envelope>
On the other hand OutFlow works more or less as it should - response looks ok but instead of "out" its direction is set as "in". If I'm not mistaken invoke method will be called for requests and revoke for responses - am I right? In my case both are using invoke. Any ideas what I'm doing wrong?
Edit:
My handler code:
public class LogHandler extends AbstractHandler implements Handler {
private Logger log = Logger.getLogger(LogHandler.class.toString());
#Override
public void init(HandlerDescription handlerDescription) {
super.init(handlerDescription);
}
public InvocationResponse invoke(MessageContext msgContext) throws AxisFault {
System.out.println("invoked: " + msgContext.getEnvelope().toString() + "\n");
log.info("invoked: " + msgContext.getEnvelope().toString() + "\n");
return InvocationResponse.CONTINUE;
}
public void revoke(MessageContext msgContext) {
log.info("revoked: " + msgContext.getEnvelope().toString() + "\n");
}
}
Module:
public class LoggingModule implements Module {
private static final Log log = LogFactory.getLog(LoggingModule.class);
// initialize the module
public void init(ConfigurationContext configContext, AxisModule module) throws AxisFault {
}
public void engageNotify(AxisDescription axisDescription) throws AxisFault {
}
// shutdown the module
public void shutdown(ConfigurationContext configurationContext) throws AxisFault {
}
public String[] getPolicyNamespaces() {
return null;
}
public void applyPolicy(Policy policy, AxisDescription axisDescription) throws AxisFault {
}
public boolean canSupportAssertion(Assertion assertion) {
return true;
}
}
module.xml:
<module name="sample-logging" class="pl.wso2.logging.LoggingModule">
<InFlow>
<handler name="InFlowLogHandler" class="pl.wso2.logging.LogHandler">
<order phase="loggingPhase"/>
</handler>
</InFlow>
<OutFlow>
<handler name="OutFlowLogHandler" class="pl.wso2.logging.LogHandler">
<order phase="loggingPhase"/>
</handler>
</OutFlow>
</module>
In my wso2 proxy I use Payload Mediator to create response and then return it using Respond Mediator.
For given request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<aa>blahblah</aa>
</soapenv:Body>
</soapenv:Envelope>
there two thing logged:
request from InFlow
invoked: <?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlso
ap.org/soap/envelope/"><soapenv:Body/></soapenv:Envelope>
and response from OutFlow
invoked: <?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlso
ap.org/soap/envelope/"><soapenv:Body><m:checkpriceresponse xmlns:m="http://services.samples/xsd"><m:
code>dsadsa</m:code></m:checkpriceresponse></soapenv:Body></soapenv:Envelope>
As per https://axis.apache.org/axis2/java/core/docs/modules.html#Step2_:_LogHandler ...
"public void invoke(MessageContext ctx);" is the method that is called
by the Axis2 engine when the control is passed to the handler. "public
void revoke(MessageContext ctx);" is called when the handlers are
revoked by the Axis2 engine."
which means since you are calling same handler in both InFlow and OutFlow the same invoke() method should be getting triggered for both the request and the response. If you want different logics to be executed for requests and responses maybe you should write separate handlers for request and response.
After debugging everything I've found that while request was parsed in InFlow, instead of using its soap message, new one (empty) was created. Thankfully it's possible to access proper request using soap tracer handler (or just its code).
I'm trying to create an inbound gateway for a SOAP service, that accepts SOAP requests like the following:
<?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Header>
<RequestHeader xmlns="http://test.com/">
<SecurityToken>mytoken</SecurityToken>
<RequestID>1234</RequestID>
</RequestHeader>
</S:Header>
<S:Body>
<BaseRequest xmlns="http://test.com/">
<RequestData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="BalanceRequest">
<CustomerID>1234</CustomerID>
</RequestData>
</BaseRequest>
</S:Body>
</S:Envelope>
I want to use JAXB for marshalling/unmarshalling the request/response. I have managed to configure Spring/Spring-integration with the following:
<oxm:jaxb2-marshaller id="soapMarshaller" context-path="com.test" />
<int:channel id="soap-channel"/>
<int-ws:inbound-gateway id="ws-inbound-gateway"
request-channel="soap-channel"
marshaller="soapMarshaller"/>
<int:service-activator input-channel="soap-channel">
<bean class="com.test.SoapServiceActivator"/>
</int:service-activator>
And I have tried to extract the SOAP header and body in the service activator.
#ServiceActivator
public BaseResponse issueResponseFor(BaseRequest body,
#Headers Map<String, Object> headerMap) {
return null;
}
BaseRequest is a JAXB annotated class.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"requestData"
})
#XmlRootElement(name = "BaseRequest")
public class BaseRequest {
#XmlElement(name = "RequestData")
protected BaseRequestBody requestData;
}
My problem is that in the variable body, I get the body of the SOAP request, but I didn't find anyway to extract the headers of the SOAP request. The headerMap variable holds only the standard Spring-Integration headers (replyChannel, errorChannel, id, timestamp). By headers, I mean the SecurityToken+RequestID, and also the HTTP header with the name of the requested action.
Any idea how to do that ?
Try to use mapped-request-headers="*".
By default the the DefaultSoapHeaderMapper maps only standard headers. And in this case it is only WebServiceHeaders.SOAP_ACTION
UPDATE
Quoting Omar :-)
Thanks ! The following code is working great :
#Autowired
#Qualifier("soapMarshaller")
Jaxb2Marshaller marshaller;
#ServiceActivator
public BaseResponse issueResponseFor(BaseRequest request, #Header("RequestHeader") SoapHeaderElement soapHeader) {
BaseRequestHeader requestHeader = (BaseRequestHeader) JAXBIntrospector.getValue(marshaller.unmarshal(soapHeader.getSource()));`
So I have mapped a WSO2 DSS service through WSO2 ESB. I have generated a jax-ws client and I am using it successfully to get some data.
The problem is that sometimes when I call the client it throws a
Exception in thread "main" java.lang.NullPointerException
at com.sirmaitt.egov.codelist.client.Client.main(Client.java:77)
At that line of the source code I am trying to print the response data in the console.
Here's the code I'm using to call the service
// Initialize service
Codelists_Service service = new Codelists_Service();
// Adds custom handler so we can add custom SOAP security header.
service.setHandlerResolver(new HandlerResolver() {
#SuppressWarnings("rawtypes")
public List<Handler> getHandlerChain(PortInfo portInfo) {
List<Handler> handlers = new ArrayList<Handler>();
handlers.add(new SecuritySOAPHandler());
return handlers;
}
});
CodelistsPortType port = service.getCodelistsHttpsSoap11Endpoint();
Codelists codelists = null;
try {
codelists = port.getcodelists();
} catch (DataServiceFault e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Prints the response.
for (Codelist cList : codelists.getCodelist()) {
}
Rest of the project are mainly jax-ws generated classes and one custom SOAPHandler, which I use to add a security header.
The issue is that this same client actually starts working when I log in the WSO2 ESB and click on the service I've mapped there. And it throws exception when I don't use the service for some time.
This issue really puzzles me. What can be the cause of it?
EDIT: Clarification, the code on line 77 is the for loop. It seems the codelists object is null.
EDIT: Here's the method that adds the security header to the request.
public boolean handleMessage(SOAPMessageContext messageContext) {
Boolean isOutboundMessage = (Boolean) messageContext
.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (isOutboundMessage) {
SOAPPart messageSoapPart = messageContext.getMessage()
.getSOAPPart();
WSSecHeader securityHeader = new WSSecHeader();
securityHeader.insertSecurityHeader(messageSoapPart);
WSSecUsernameToken usernameToken = new WSSecUsernameToken();
usernameToken.setPasswordType(WSConstants.PASSWORD_TEXT);
usernameToken.setUserInfo(USER_NAME, PASSWORD);
WSSecTimestamp timestamp = new WSSecTimestamp();
usernameToken.build(messageSoapPart, securityHeader);
timestamp.build(messageSoapPart, securityHeader);
}
return true;
}
And here is what the request looks like (taken from console)
---[HTTP request]---
SOAPAction: "urn:_getcodelists"
Accept: text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Content-Type: text/xml;charset="utf-8"
<?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Header><wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" S:mustUnderstand="1"><wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-11800260"><wsu:Created>2012-09-18T13:17:56.707Z</wsu:Created><wsu:Expires>2012-09-18T13:22:56.707Z</wsu:Expires></wsu:Timestamp><wsse:UsernameToken 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" wsu:Id="UsernameToken-9299042"><wsse:Username>admin</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">admin</wsse:Password></wsse:UsernameToken></wsse:Security></S:Header><S:Body></S:Body></S:Envelope>--------------------
---[HTTP response 202]---
Transfer-encoding: chunked
null: HTTP/1.1 202 Accepted
Connection: keep-alive
Server: Synapse-HttpComponents-NIO
Date: Tue, 18 Sep 2012 13:19:57 GMT
I think it is because your session timed out and you needed to log in again to authenticate the service.