I am about to develop web application with web services. I've already tuned jax-ws and ws-security. I used soapUI and sent next request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="..." >
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv: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-2">
<wsu:Created>2011-11-11T00:05:05.044Z</wsu:Created>
<wsu:Expires>2012-11-11T00:10:05.044Z</wsu:Expires>
</wsu:Timestamp>
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="UsernameToken-1">
<wsse:Username>user</wsse:Username>
<wsse:Password>password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<soap:foo>
<arg0>1</arg0>
</soap:foo>
</soapenv:Body>
</soapenv:Envelope>
I need get Username and Password from header. On the application I can get it by next code:
#Resource
WebServiceContext context;
...
private static final String PRINCIPAL_RESULT = "wss4j.principal.result";
...
WSUsernameTokenPrincipal wsutp = (WSUsernameTokenPrincipal) context.getMessageContext().get(PRINCIPAL_RESULT);
..
String user = wsutp.getName()
String password = wsutp.getPassword();
But I have no idea how should I test it with jUnit tests, because context.getMessageContext() will be NULL on test class.
Does anyone knows a good guide or provide a code-sample?
You need to mock the resources, that are not available in your junit tests. Please have a look at a framework like Mokito (http://mockito.org/). There you can do s.th. like:
//You can mock concrete classes, not only interfaces
LinkedList mockedList = mock(LinkedList.class);
//stubbing
when(mockedList.get(0)).thenReturn("first");
when(mockedList.get(1)).thenThrow(new RuntimeException());
Or for your case:
WSUsernameTokenPrincipal mockedWsutp = mock(WSUsernameTokenPrincipal.class);
when(mockedWsutp.getName()).thenReturn("TheNameRequiredForYourTestCase");
...
With these frameworks, you can simulate the unavailable resources. And they integrate easily with junit. I hope this provides some useful ideas.
Try this:
JAX-WS Webservice secured With XWS-Security (plain text password)
[http://mananvpanchal.blogspot.com/2010/06/jax-ws-webservice-with-plaintext.html][1]
Related
I have a Soap service generated by a wsdl file, that expects a certain TargetNamespace
#WebResult(name = "getResponse", targetNamespace = "http://targetNameSpace1.com", partName = "result")
but we have multiple clients calling this api and each one uses a diferente TargetNamespace:
Client one:
<soap:Envelope
xmlns:loc="http://targetNameSpace1.com">
<soap:Header>
<ns3:RequestSOAPHeader>
...
</ns3:RequestSOAPHeader>
</soap:Header>
<soap:Body>
<loc:getResponse>
<loc:value>url/</loc:value>
</loc:getResponse>
</soap:Body>
</soap:Envelope>
Client two:
<soap:Envelope
xmlns:loc="http://targetNameSpace2.com">
<soap:Header>
<ns3:RequestSOAPHeader>
...
</ns3:RequestSOAPHeader>
</soap:Header>
<soap:Body>
<loc:getResponse>
<loc:value>url/</loc:value>
</loc:getResponse>
</soap:Body>
</soap:Envelope>
This is the error i get:
<soap:Envelope>
<soap:Body>
<soap:Fault>
<faultcode>soap:Client</faultcode>
<faultstring>Message part {http://targetNameSpace2.com}getResponse was not recognized. (Does it exist in service WSDL?)</faultstring>
</soap:Fault>
</soap:Body>
</soap:Envelope>
and i can only make it work with one at a time changing the targetNameSpace tag in the webResult, but my ultimate goal is to ignore this tag, because i dont know witch namespace will each client use.
At the moment i am trying to use an interceptor that extends this
AbstractSoapInterceptor and i get a SoapMessage object i can acess it before the request is made, but i can't seem to change the request, not sure if its the best aproach.
Does anyone have a solution for this?
Thanks!
The wsdl and the (embedded) xsd are the contracts that you specify. Server and client need to follow that contract. Changing the contract single sided will result into invalid messages. Instead of looking for a solution to accept invalid messages you should update the clients so they obey the contracts.
I ended up following this article https://www.javatips.net/blog/cxf-interceptor-example,
I intercept every request, and replace this:
xmlns:loc="http://targetNameSpace2.com"
with the url that i want, i used regex to replace whats inside the loc tag
I have created a web service using JAX-WS and trying to add Simple UsernameToken security to the web service. The application is deployed on Websphere 8.5.
I found the following link which helps to add the usernameToken from RAD -> Services tab quite easily for JAX-RPC based web services but the same feature is not available for JAX-WS type web services.
RAD - How to add username token for JAX RPC in websphere application server admin console
Can anybody help to provide some similar kind of steps or another possible simple solution to achieve the same for JAX-WS web services?
<Soapenv:Header>
<wsse:Security soapenv: mustUnderstand="1"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wsswssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>user</wsse: Username>
<wsse:Password
Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wssusername-token-profile-1.0#PasswordText">paas</wsse: Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
Thanks.
Finally, I have managed to find a workaround for the problem above. Its as follows:
After googling a lot I came across a concept of Web-service Handler which can be invoked for every request and response that is either received or sent from the Webservice Provider respectively.
How to configure:
1. Create a Java File SecurityHandler and paste the following code in it:
public class SecurityHandler implements SOAPHandler<SOAPMessageContext>
{
#Override
public boolean handleMessage(SOAPMessageContext context)
{
boolean outbound = (Boolean)context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY);
if(outbound) {
//logic to handle a response
}
if (!outbound) {
//logic to handle a request
}
return true;
}
#Override
public boolean handleFault(SOAPMessageContext context) {
return true;
}
#Override
public void close(MessageContext context) {}
#Override
public Set<QName> getHeaders() {
return Collections.emptySet();
}
}
Create an XML file with below code sample:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<javaee:handler-chains
xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<javaee:handler-chain>
<javaee:handler>
<javaee:handler-class>your.package.path.SecurityHandler</javaee:handler-class>
</javaee:handler>
</javaee:handler-chain>
</javaee:handler-chains>
To activate the handler on each request or response to the web service you exposed add the annotation in your web service class as follows:
#HandlerChain(file="/your/package/path/handler-chain.xml")
public class my web services {
//methods or web-services to be exposed.
}
I am using Camel in our project and requesting WebServices, the dataFormat is POJO. I was able to request when my SOAP message did not contain SOAP headers, but when it had Headers, I was unable to set those. I looked at the documentation but was not able to understand and have several questions.
I want to create a message like the below:
<soapenv:Envelope`enter code here`
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header>
<platformMsgs:documentInfo
xmlns:platformMsgs="urn:messages_2015_1.platform.webservices.netsuite.com">
<platformMsgs:nsId>WEBSERVICES_3479023</platformMsgs:nsId>
</platformMsgs:documentInfo>
</soapenv:Header>
<soapenv:Body>
<addListResponse
xmlns="">
<platformMsgs:writeResponseList
xmlns:platformMsgs="urn:messages_2015_1.platform.webservices.netsuite.com">
<platformCore:status isSuccess="true"
xmlns:platformCore="urn:core_2015_1.platform.webservices.netsuite.com"/>
<platformMsgs:writeResponse>
<platformCore:status isSuccess="false"
xmlns:platformCore="urn:core_2015_1.platform.webservices.netsuite.com">
<platformCore:statusDetail type="ERROR">
<platformCore:code>DUP_ENTITY</platformCore:code>
<platformCore:message>This entity already exists.</platformCore:message>
</platformCore:statusDetail>
</platformCore:status>
</platformMsgs:writeResponse>
</platformMsgs:writeResponseList>
</addListResponse>`enter code here`
</soapenv:Body>
</soapenv:Envelope>
I will be able to send the message if there was only Body, but can someone give me a code snippet for including the header section? The dataFormat is POJO.
When using CXF endpoint with dataFormat as POJO, body in Camel Exchange object is an object of org.apache.cxf.message.MessageContentsList. It is an extension of java.util.ArrayList<Object> and it contains parts of SOAP Message in order as defined in WSDL and corresponding method in WebService class.
Element 0 there is a Body.
So, one way to do that with Java is to create a Processor class implementing org.apache.camel.Processor interface and in its process method set your SOAP header. Something like:
#Override
public void process(Exchange camelExchange) throws Exception {
MessageContentsList messageBody = (MessageContentsList) camelExchange.getIn().getBody();
DocumentInfo docInfoHeader = new DocumentInfo();
... set docInfoHeader properties ...
messageBody.add(docInfoHeader);
}
(sample is not tested. It is just an idea, how to handle that...)
Other answer on similar question you can find here: Setting Custom Soap Header-To Pojo Message In Camel Cxf
It describes how to use Camel Exchange headers as SOAP Headers.
I'm not sure for 100% which way will work for you and which one is better...
I guess, it depends on WSDL you use.
UPD: second choice is to use pure CXF solution by using CxfMessageSoapHeaderOutInterceptor custom implementation.
It may look like:
public class MyCxfInterceptor extends CxfMessageSoapHeaderOutInterceptor {
#Override
public void handleMessage( org.apache.cxf.binding.soap.SoapMessage message) {
org.apache.cxf.binding.soap.SoapHeader myCustomHeader = new org.apache.cxf.binding.soap.SoapHeader(new QName(
{custom name space}, {custom local name}), {Custom content object}));
myCustomHeader.setMustUnderstand(true);
message.getHeaders().add(myCustomHeader);
}
and set Interceptor in Camel Cxf Endpoint as :
<cxfEndpoint ...>
<outInterceptors>
<spring:bean class="MyCxfInterceptor"/>
</outInterceptors>
...
Well suppose I request the Web Service and it failed, a Fault message is generated. Will I get the Fault object at position 0 of MessageContentsList then too? Or will I get only the response object at position 0?
So I have a web service with several namespaces that I would like to route through a bean to do some checking of user credentials. Its been a long time since I used XPATH so I might just be having a PICNIC(Problem In Chair Not In Computer Moment) error.
The web service message will always have the following structure/pattern :
<Operation>
<header with the head name space where the user credentials are stored>
<record control>
<objXX>
</Operation>
Here is a example message(SOAP UI):
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:list="http://www.insol.irix.com.au/IRIX_V1/Debtors/List" xmlns:head="http://www.insol.irix.com.au/IRIX_V1/Headers" xmlns:rec="http://www.insol.irix.com.au/IRIX_V1/RecordControl">
<soapenv:Header/>
<soapenv:Body>
<list:ListDebtorReq>
<head:MsgReqHdr>
<head:MsgGUID>${=java.util.UUID.randomUUID()}</head:MsgGUID>
<head:MsgDateTime>${=javax.xml.datatype.DatatypeFactory.newInstance().newXMLGregorianCalendar(GregorianCalendar.getInstance())}</head:MsgDateTime>
<head:ConsumerSystemIDInfo>
<head:ConsumerSystemID>ConsumerSystemID</head:ConsumerSystemID>
<head:ConsumerSystemUserID>AgentX</head:ConsumerSystemUserID>
</head:ConsumerSystemIDInfo>
<head:SecCredInfo>
<head:IRIXUserID>Some User ID</head:IRIXUserID>
<head:IRIXPassword>Some Password</head:IRIXPassword>
</head:SecCredInfo>
<head:CryptoInfo>
<head:DigitalSignatureInfo>
<head:DigitalSignatureValue>verrantque per auras</head:DigitalSignatureValue>
<head:DigitalSignatureAlgorithm>SHA-256</head:DigitalSignatureAlgorithm>
</head:DigitalSignatureInfo>
</head:CryptoInfo>
</head:MsgReqHdr>
<!--Optional:-->
<rec:RecCntrl>
<rec:StartRecordNumber>1</rec:StartRecordNumber>
<!--Optional:-->
<rec:NumberOfRecords>3</rec:NumberOfRecords>
</rec:RecCntrl>
</list:ListDebtorReq>
</soapenv:Body>
</soapenv:Envelope>
So essentially I want to be able to create a bean that will be able to query the MsgReq header for all the user name and password data. To simplify things I am just trying to query the MsgGUID and work my way from there. However I cant seem to get the xpath right. Since I am using several namespaces I have included them in the camel context file just to make sure they are available.
Here is my camel-context:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:camel="http://camel.apache.org/schema/spring"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd">
<import resource="classpath:META-INF/spring/camel-cxf.xml" />
<bean id="SecurityCheckBean" class="au.com.irix.insol.Security.IRIXSecurity"/>
<camelContext xmlns="http://camel.apache.org/schema/spring"
xmlns:list="http://www.insol.irix.com.au/IRIX_V1/Debtors/List"
xmlns:head="http://www.insol.irix.com.au/IRIX_V1/Headers"
xmlns:rec="http://www.insol.irix.com.au/IRIX_V1/RecordControl">
<route>
<from uri="cxf:bean:DebtorsService?dataFormat=PAYLOAD"/>
<bean ref="SecurityCheckBean"/>
</route>
</camelContext>
</beans>
As you can see I am running the incoming message of the web service producer to the SecurityCheckBean. My SecurityCheckBean is super simple at the moment see code below.
public class IRIXSecurity {
public void CheckCredentials(
#XPath("//head:MsgGUID") String msgGUID,
#Body String body){
System.out.println(body);
System.out.println("Check Credentials Invoked");
System.out.println(msgGUID);
}
}
However when I send a send a request via soap UI I get the following exception:
Invalid xpath: //head:MsgGUID. Reason: javax.xml.xpath.XPathExpressionException: net.sf.saxon.trans.XPathException: Prefix head has not been declared
So how do I go about retrieving this information? Why even though I have declared the name spaces in my camel-context.xml they are reported as missing?
Just for interest sake I have tried several variations of the XPATH such as:
#XPath("//MsgGUID")
#XPath("//MsgReqHdr/head:MsgGUID")
#XPath("//head:MsgReqHdr/head:MsgGUID")
Every time I either get an exception as listed above or a NULL value...
Right got it to work. When dealing with the namespaces in a bean the following syntax must be used to include the namespaces.
public class IRIXSecurity {
public void CheckCredentials(
//#Body ListDebtorReqType msgBody, #Headers Map hdr,
#XPath(value="//header:MsgGUID",namespaces = #NamespacePrefix(
prefix = "header",
uri = "http://www.insol.irix.com.au/IRIX_V1/Headers")) String msgGUID,
#Body Document xml)
{
System.out.println("Check Credentials Invoked");
System.out.println(msgGUID);
//exchange.getOut().setBody(debtorRsType);
}
}
I have a jaxws webservice with #SchemaValidation on it.
#SchemaValidation(handler = MySchemaValidationHandler.class)
#WebService(portName = "MyService", serviceName = "MyService", targetNamespace = "urn:com.my.urn", wsdlLocation = "/wsdls/mywsdl.wsdl", endpointInterface = "com.my.MyService")
#BindingType("http://schemas.xmlsoap.org/wsdl/soap/http")
public class MyServiceImpl
implements MyService {
#Resource
WebServiceContext wsContext;
public void myOperation(Holder<XMLGregorianCalendar> tag1, Holder<XMLGregorianCalendar> tag2, Holder<String> message) {
...
}
}
in xsd I have the following example:
<xsd:choice>
<xsd:element name="tag1" type="xsd:dateTime" minOccurs="0"/>
<xsd:element name="tag2" type="xsd:dateTime" minOccurs="0"/>
</xsd:choice>
When I send the request with empty tags, I get an error concerning the field format (doesn't fit the restrictions of a date format).
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:com.my.urn">
<soapenv:Header/>
<soapenv:Body>
<urn:myOperation>
<Tag1>value1</Tag1>
<Tag2></Tag2>
</urn:myOperation>
</soapenv:Body>
</soapenv:Envelope>
In request description I have mandatory tags and choice tags and have to return the correct error message in the response, so I can't just skip such errors in the handler.
Also I can't modify nor xsd nor wsdl
Logically empty tags mean the same as missing tags. How can I make the validation treat empty tags as missing or how can I delete empty tags before the validation?
Thanks.
Edit: Don't send invalid XML. In the example you give, you should remove <Tag2></Tag2> in whatever your client code is. Don't try to abuse the server's validation to handle invalid XML.