I've two questions about Ksoap2.
First at all, below an example of my webservice request in XML.
REQUEST:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://my-webservice.com/">
<soapenv:Header/>
<soapenv:Body>
<web:getBoard>
<!--Optional:-->
<language></language>
<identification login="" pwd=""/>
</web:getBoard>
</soapenv:Body>
</soapenv:Envelope>
RESPONSE:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:getBoardResponse xmlns:ns2="http://my-webservice.com/">
<board code="NONE">WhatIWant</board>
<board code="HALF">blabla</board>
<board code="FULL">blablah</board>
<board code="RONL">blablalblba</board>
<board code="BRKF">blabla</board>
<board code="ALLI">blablablah</board>
</ns2:getBoardResponse>
</soap:Body>
</soap:Envelope>
I have to set datas for the fields: "language", "login" and "pwd" but i'm not sure to use the good method... (addProperty or setProperty for the field "language" ?)
public class CallRefservices {
private static final String NAMESPACE = "http://api.myapi.com/test/ws/test";
private static final String URL = "http://api.myapi.com/test/ws/test?wsdl";
private static final String SOAP_ACTION = "getBoard";
private static final String METHOD_NAME = "getBoard";
Boolean getConnection(String login, String pwd) {
Boolean checkBoardType = false;
try {
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
request.addProperty("login", login);
request.addProperty("pwd", pwd);
request.addProperty("language", "FR");
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.call(SOAP_ACTION, envelope);
SoapObject objetSOAP = (SoapObject)envelope.getResponse();
checkBoardType = this.parserObjet(objetSOAP);
} catch (Exception e) {
Log.e("getConnection", "", e);
}
return checkBoardType;
}
private boolean parserObjet(SoapObject objet) {
SoapObject boardObjet = (SoapObject)objet.getProperty("board");
String board = boardObjet.getProperty("NONE").toString();
if (board == "WhatIWant")
return true;
else
return false;
}
}
I also need help about the parser.
what kind of parser is use with Ksoap2? (DOM, SAX)
Am I using the good method?
any help is appreciated!
merry christmas btw ;).
EDIT:
Well, my problem is that the xml sent is the following:
[...] <login i:type="d:string">mylogin</login><pwd i:type="d:string">mypassword</pwd><language i:type="d:string">FR</language></n0:getBoardTypes></v:Body></v:Envelope>
Whereas I need:
[...] <language></language>
<identification login="" pwd=""/>
:|
EDIT 2:
Hi Tomislav, thanks for your time and your answer !
I tried your solution but it can't works.
I'm suppose to send something like:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://my.api.com/">
<soapenv:Header/>
<soapenv:Body>
<web:getBoard>
<language>FR</language>
<identification login="username" pwd="mypwd"/>
</web:getBoard>
</soapenv:Body>
</soapenv:Envelope>
With your solution i've something like:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://my.api.com/">
<soapenv:Header/>
<soapenv:Body>
<web:getBoard>
<language>FR</language>
<identification>
<login>username</login>
<pwd>mypwd</pwd>
</identification>
</web:getBoard>
</soapenv:Body>
</soapenv:Envelope>
I think that I gonna create a XML template... :/ !
So I assume your service method signature is something like
getBoard(String language, identification ident) // parameter names here must match the param names in the code below
where identification is a class with two string properties login and pwd. If that's the case you can create a new class and implement KvmSerializable like below:
public class identification implements KvmSerializable {
public String login;
public String pwd;
public identification (String login, String pwd) {
this.login = login;
this.pwd = pwd;
}
public Object getProperty(int i) {
switch (i) {
case 0:
return login;
case 1:
return pwd;
}
return null;
}
public int getPropertyCount() {
return 2;
}
public void setProperty(int i, Object o) {
switch (i) {
case 0:
login = o.toString();
break;
case 1:
pwd = o.toString();
break;
}
}
public void getPropertyInfo(int i, Hashtable hashtable, PropertyInfo propertyInfo) {
switch (i) {
case 0:
propertyInfo.type = PropertyInfo.STRING_CLASS;
propertyInfo.name = "login";
break;
case 1:
propertyInfo.type = PropertyInfo.STRING_CLASS;
propertyInfo.name = "pwd";
break;
}
}
}
And then add this property like the following:
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
request.addProperty("language", "FR");
PropertyInfo info = new PropertyInfo();
info.setName("identification"); // you have to make sure here that the parameter name matches the one in the WSDL, which you havent posted
info.setType(identification.class);
info.setValue(new identification("username", "password"));
request.addProperty(info);
Related
I am trying to extract custom SOAP header using the chain-handler mechanism as below:
Webservice:
`#HandlerChain(file="handler-chain.xml")
public class CustomAPI extends SessionBeanBase {
#WebMethod
public GetBalanceResponse getBalances(
#WebParam(name="subscriptionId")long subscriptionId,
#WebParam(name="validityPeriodFromDt")Date validityPeriodFromDt,
#WebParam(name="validityPeriodToDt")Date validityPeriodToDt) throws APIException
{
try {
GetBalancesItem item = new GetBalancesItem(subscriptionId, validityPeriodFromDt, validityPeriodToDt);
final BalanceBusinessLogic api = (BalanceBusinessLogic)startCall(RSLogic.class, this, "getBalances");
BusinessLogicCallable<GetBalancesItem> t = new BusinessLogicCallable<GetBalancesItem>() {
public Response callBusinessLogic(GetBalancesItem getBalancesItem) throws CCSException, APIException {
Date validityPeriodFromDt = getBalancesItem.getValidityPeriodFromDt();
Date validityPeriodToDt = getBalancesItem.getValidityPeriodToDt();
long subscriptionId = getBalancesItem.getSubscriptionId();
return api.checkBalance(subscriptionId, validityPeriodFromDt, validityPeriodToDt);
}
};
return (GetBalanceResponse)callBusinessLogic(t, item);
} catch (Throwable e) {
// Handle exception (and rethrow it hence the need for return null)
handleExceptions(e);
return null;
}
}`
Handler-chain. xml as:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<handler-chains xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/javaee_web_services_metadata_handler_2_0.xsd">
<handler-chain>
<handler>
<handler-name>ApiSoapHandler</handler-name>
<handler-class>com.api.framework.ApiSoapHandler</handler-class>
</handler>
</handler-chain>
</handler-chains>
ApiSOAPhandlercode as:
public boolean handleMessage(SOAPMessageContext context) {
logger.debug("Inside ApiSoapHandler");
try {
SOAPMessage message = context.getMessage();
SOAPPart soapPart= message.getSOAPPart();
SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
if (soapEnvelope.getHeader() == null) {
soapEnvelope.addHeader();
}
// set the soap header
SOAPHeader latestSOAPHeader = soapHeader.get();
if (latestSOAPHeader != null) {
Iterator iterator = latestSOAPHeader.getChildElements();
while(iterator.hasNext()) {
SOAPHeaderElement soapHeaderElement = (SOAPHeaderElement)iterator.next();
soapEnvelope.getHeader().addChildElement(soapHeaderElement);
}
}
message.saveChanges();
System.out.println("header" + header.getAttribute("token"));
} catch (Exception e) {
logger.error("Error occurred while adding credentials to SOAP header.",
e);
}
return true;
}
The problem is that my header is fetched as null here . can anyone please suggest how to get the header here . For the reference , here is my sample SOAP request :
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:bal="http://balance.api.ccs.cerillion.com/">
<soapenv:Header>
<token>187328364</token>
<soapenv:Header/>
<soapenv:Body>
<bal:getBalances>
<subscriptionId>664</subscriptionId>
</bal:getBalances>
</soapenv:Body>
</soapenv:Envelope>
While extracting token , am getting null in my code .
I have a problem with WS-Addresing in SOAP header. I succesfully imported classes from xsd file with configuration, but server require WS-Addressing attributes in soap header("wsa:action", "wsa:to"). Unfortunettly client service dont inject these attributes and server return http code 400 "Bad Request".
How can I automatically inject a proper SOAP header for requests?
I tried with #Addressing(enabled=true, required=true) annotation, but header was wrong for webservice
Configuration in Config.groovy
Service endpoint: https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc
Main xsd file: https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/wsdl/UslugaBIRzewnPubl.xsd
I use Grails 2.5.0 and plugin grails-cfx
Grails-cfx configuration in Config.groovy
birCompanyDataEndPoint {
wsdl = "wsdl/UslugaBIRzewnPubl.xsd"
namespace = "pl.truesoftware.crm.company.regon"
client = true
contentType = "application/soap+xml"
mtomEnabled = true
exsh = true
or = true
wsdlArgs = ['-autoNameResolution']
// outInterceptors = 'smartApiMetaOutInterceptor'
clientInterface = IUslugaBIRzewnPubl
serviceEndpointAddress = "https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc"
}
Example
Plain SOAP request from client service
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:DaneKomunikat xmlns="http://CIS/BIR/PUBL/2014/07/DataContract" xmlns:ns2="http://CIS/BIR/PUBL/2014/07" xmlns:ns3="http://CIS/BIR/2014/07" xmlns:ns4="http://schemas.microsoft.com/2003/10/Serialization/"/>
</soap:Body>
</soap:Envelope>
With using annotation #Addressing(enabled=true, required=true)
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<Action xmlns="http://www.w3.org/2005/08/addressing">http://CIS/BIR/PUBL/2014/07/IUslugaBIRzewnPubl/DaneKomunikat</Action>
<MessageID xmlns="http://www.w3.org/2005/08/addressing">urn:uuid:f43e7c86-99dd-42fc-a626-ccbd44136682</MessageID>
<To xmlns="http://www.w3.org/2005/08/addressing">https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc</To>
<ReplyTo xmlns="http://www.w3.org/2005/08/addressing">
<Address>http://www.w3.org/2005/08/addressing/anonymous</Address>
</ReplyTo>
</soap:Header>
<soap:Body>
<ns2:DaneKomunikat xmlns="http://CIS/BIR/PUBL/2014/07/DataContract" xmlns:ns2="http://CIS/BIR/PUBL/2014/07" xmlns:ns3="http://CIS/BIR/2014/07" xmlns:ns4="http://schemas.microsoft.com/2003/10/Serialization/"/>
</soap:Body>
</soap:Envelope>
Expected
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://CIS/BIR/PUBL/2014/07">
<soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:To>https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc</wsa:To>
<wsa:Action>http://CIS/BIR/PUBL/2014/07/IUslugaBIRzewnPubl/DaneKomunikat</wsa:Action>
</soap:Header>
<soap:Body>
<ns:DaneKomunikat/>
</soap:Body>
</soap:Envelope>
Update with solution
Created two cfx interceptor. First convert soap addressing tags(Action, To) to acceptable format
public class BirSoapHeaderInterceptor extends AbstractSoapInterceptor
{
static String birSID = ""
public BirSoapHeaderInterceptor() {
super(Phase.PRE_PROTOCOL);
}
#Override
public void handleMessage(SoapMessage message) throws Fault
{
try
{
message.put("disable.outputstream.optimization", true)
List<Header> soapHeaders = message.getHeaders()
//----------------- copy values from old header
String wsaAction = ""
String wsaTo = ""
soapHeaders.each { tag ->
log.debug("Soap request header tag: ${tag.name} ${tag.dataBinding}")
String tagName = (tag.name as String)
def objectValue = tag.object?.value
if (!wsaAction && tagName.contains("Action"))
wsaAction = objectValue?.value
if (!wsaTo && tagName.contains("To"))
wsaTo = objectValue?.value
}
soapHeaders.clear()
//-----------------wsa:To
Header headTo = new Header(new QName("http://www.w3.org/2005/08/addressing", "To", "wsa"), wsaTo, new JAXBDataBinding(String.class))
soapHeaders.add(headTo)
//-----------------wsa:Action
Header headAction = new Header(new QName("http://www.w3.org/2005/08/addressing", "Action", "wsa"), wsaAction, new JAXBDataBinding(String.class))
soapHeaders.add(headAction)
message.put(Header.HEADER_LIST, soapHeaders)
//Session identyficator in HTTP Header
if(birSID.length())
{
Map<String, List<String>> outHeaders = (Map<String, List<String>>) message.get(Message.PROTOCOL_HEADERS)
outHeaders.put("sid", Arrays.asList(birSID));
message.put(Message.PROTOCOL_HEADERS, outHeaders);
}
} catch (SOAPException e)
{
log.error(e)
}
}
}
Second interceptor converts attributes 'xmlns:soap', 'xmlns:wsa', 'xmlns:soap' with acceptable namespaces
class BirSoapContextInterceptor implements SOAPHandler<SOAPMessageContext>
{
/*
Based on https://stackoverflow.com/questions/10678723/changing-jax-ws-default-xml-namespace-prefix
*/
public boolean handleMessage(final SOAPMessageContext context)
{
try
{
SOAPMessage soapMsg = context.getMessage();
SOAPEnvelope envelope = soapMsg.getSOAPPart().getEnvelope()
soapMsg.getSOAPPart().getEnvelope().removeAttributeNS("http://schemas.xmlsoap.org/soap/envelope/", "soap");
soapMsg.getSOAPPart().getEnvelope().removeAttributeNS("http://www.w3.org/2000/xmlns/", "soap");
soapMsg.getSOAPPart().getEnvelope().removeAttribute("xmlns:soap");
soapMsg.getSOAPPart().getEnvelope().removeNamespaceDeclaration("xmlns:soap")
envelope.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:soap", "http://www.w3.org/2003/05/soap-envelope");
envelope.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:ns", "http://CIS/BIR/PUBL/2014/07");
soapMsg.getSOAPHeader().setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:wsa", "http://www.w3.org/2005/08/addressing")
soapMsg.getSOAPHeader().setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:soap", "http://www.w3.org/2003/05/soap-envelope");
soapMsg.saveChanges()
context.setMessage(soapMsg)
} catch (SOAPException e)
{
e.printStackTrace();
}
return true;
}
#Override
boolean handleFault(SOAPMessageContext context) {
return false
}
#Override
void close(MessageContext context) {
log.debug("Closing...")
}
#Override
Set<QName> getHeaders() {
return null
}
}
Hi i have a code for generating a simple request to a example soap server where i need to build a request like:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://10.1.5.80:8080/">
<soapenv:Header/>
<soapenv:Body>
<ns:GETSERVERTIME/>
</soapenv:Body>
</soapenv:Envelope>
but i get
<v:Envelope
xmlns:i="http://www.w3.org/1999/XMLSchema-instance"
xmlns:d="http://www.w3.org/1999/XMLSchema"
xmlns:c="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:v="http://schemas.xmlsoap.org/soap/envelope/">
<v:Header />
<v:Body>
<n0:GETSERVERTIME xmlns:n0="http://localhost:8080/" />
</v:Body>
</v:Envelope>
i Only need to change "v:" to "soapenv:"
my code:
/**
* Created by Vinicius Gati on 30/12/14.
*
*/
public class ServerSOAP {
private static final String METHOD_NAME = "GETSERVERTIME";
private static final String NAMESPACE = "http://localhost:8080/";
private static final String SOAP_ACTION = "";
private static final String URL = "http://10.1.5.80:8080/ws/SERVERTIME.apw?WSDL";
public static String getServerTime() {
String retorno = "";
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER10);
envelope.implicitTypes = false;
envelope.setAddAdornments(false);
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.debug = true;
try {
androidHttpTransport.call( NAMESPACE + METHOD_NAME, envelope );
SoapObject response = (SoapObject) envelope.getResponse();
} catch (Exception e) {
e.printStackTrace();
}
return retorno;
}
}
but i'm crazy trying this, no success.
As You may see in:
https://github.com/mosabua/ksoap2-android/blob/master/ksoap2-base/src/main/java/org/ksoap2/SoapEnvelope.java
writing method defines prefixes as string constants (code copy from class SoapEnvelope, see provided link):
public void write(XmlSerializer writer) throws IOException {
writer.setPrefix("i", xsi);
writer.setPrefix("d", xsd);
writer.setPrefix("c", enc);
writer.setPrefix("v", env);
writer.startTag(env, "Envelope");
writer.startTag(env, "Header");
writeHeader(writer);
writer.endTag(env, "Header");
writer.startTag(env, "Body");
writeBody(writer);
writer.endTag(env, "Body");
writer.endTag(env, "Envelope");
}
So, You may try to define own class, inheriting from SoapSerializationEnvelope and experiment with redefining this method to use "soapenv" prefix.
BTW: if WS cant read prefix of any name, its a poor code on this service side. "soapenv" or "v" should be interpreted as identical in both xml's You included.
Marcin
Dude,
I've solved this issue. Actually I've extend the SoapSerializationEnvelope class and overridden the SoapSerializationEnvelope's write() method as follows
#Override
public void write(XmlSerializer writer) throws IOException {
Log.d("DEBUG", "XML create process started");
env = "http://schemas.xmlsoap.org/soap/envelope/";
String tem = "http://tempuri.org/";
String ner = "http://schemas.datacontract.org/2004/07/MYSERVICE";
//writer.text("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
// Don't try like above, it will cause errors, for instead of this, you should use below code
writer.startDocument("UTF-8", true);
writer.setPrefix("soapenv", env); //these are propably same for you
writer.setPrefix("tem", tem); //these are propably same for you
writer.setPrefix("ner", ner); // but this must change with your namespace writer.setPrefix("myTag", ner);
writer.startTag(env, "Envelope");
writer.startTag(env, "Header");
writeHeader(writer);
writer.endTag(env, "Header");
writer.startTag(env, "Body");
writer.startTag(tem, "Method");
writer.startTag(tem, "inputObject");
writer.startTag(ner, "property");
writer.text("property value");
writer.endTag(ner, "property");
writeBody(writer);
writer.endTag(tem, "inputObject");
writer.endTag(tem, "Method");
writer.endTag(env, "Body");
writer.endTag(env, "Envelope");
writer.endDocument();
Log.d("DEBUG","XML created");
}
I have developed a webservice in java using Metro RI( Along with an AuthenticationHandler), But when I am sending a SOAP request to the webservice, I am not able to get the SOAPHeader in the SOAPHandler.
Below is the SOAP Request which I am passing to the webservice.(I am using SOAP UI for this purpose)
`
<soapenv:Envelope xmlns:ser="http://server.webservice.bank/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-4" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>kshitij.jain</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">Phone0144</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">jf97anyZJUpR216tw4GRIw==</wsse:Nonce>
<wsu:Created>2013-05-15T17:38:49.610Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<ser:getCreditCardTransaction>
<cardId>2</cardId>
<amt>109</amt>
<!--Optional:-->
<descr>test</descr>
</ser:getCreditCardTransaction>
</soapenv:Body>
</soapenv:Envelope>
`
Following is my code for webservice and Handler :
`
#WebService(serviceName = "getTransaction")
#HandlerChain(file = "ServerHandler.xml")
public class getTransaction {
#Inject
TransactionService tranService;
#Resource
private WebServiceContext wsContext;
#WebMethod(operationName = "getCreditCardTransaction")
public CreCardTranResponse getCreditCardTransaction(#WebParam(name = "cardId") int cardId, #WebParam(name = "amt") int amt, #WebParam(name = "descr") String descr) {
CreCardTranResponse res = new CreCardTranResponse();
tranService.addTransaction(amt, descr, "Debit", cardId);
res.setAmtDeducted(new Integer(amt).toString());
res.setCardID(new Integer(cardId).toString());
ReturnMessage ret = new ReturnMessage();
ret.setReturnCode("0");
ret.setReturnMessage("Successful");
res.setRetMessage(ret);
return res;
}
}
`
`
public class AuthenticationHandler implements SOAPHandler<SOAPMessageContext> {
private static Set<QName> headers;
static {
HashSet<QName> set = new HashSet<QName>();
set.add(new QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security"));
headers = Collections.unmodifiableSet(set);
}
#Override
public Set<QName> getHeaders() {
return headers;
}
#Override
public boolean handleMessage(SOAPMessageContext context) {
try {
handleSecurityMessage(context);
} catch (SOAPException ex) {
}
return true;
}
public boolean handleSecurityMessage(SOAPMessageContext context) throws SOAPException {
SOAPHeader soapHeader = context.getMessage().getSOAPHeader();
SOAPFault fault = SOAPFactory.newInstance().createFault();
if (soapHeader == null) {
fault.setFaultCode("failed");
fault.setFaultString("Soap header missing");
throw new SOAPFaultException(fault);
}
return true;
}
#Override
public boolean handleFault(SOAPMessageContext context) {
return true;
}
#Override
public void close(MessageContext context) {
}
}
`
Below is the serverHandler.xml
`
<?xml version="1.0" encoding="UTF-8"?>
<handler-config>
<handler-chain>
<handler-chain-name>AuthenticationHandlerChain</handler-chain-name>
<handler>
<handler-name>AuthenticationHandler</handler-name>
<handler-class>bank.webservice.security.AuthenticationHandler</handler-class>
</handler>
</handler-chain>
</handler-config>
`
I have already wasted 2 days on this, But After adding the header from SOAP UI also, code is showing header as null .
Is it the problem with SOAP UI or with the code?
I have a class that implements the SOAPHandler interface. The handleMessage is defined as:
public boolean handleMessage(SOAPMessageContext context) {
SOAPMessage msg = context.getMessage();
SOAPPart part = msg.getSOAPPart();
SOAPEnvelope envelope = part.getEnvelope();
// add namespaces
SOAPElement envelope.addNamespaceDeclaration("xsd", "http://www.w3.org/2001/XMLSchema");
envelope.addNamespaceDeclaration("xsi", "http://www.w3.org/2001/XMLSchema-
// add the header with additional elements
Name qname = envelope.createName("Security", "sse", "http://example.com/security.xsd");
element = envelope.addHeader().addChildElement(qname);
qname = envelope.createName("mustUnderstand");
element.addAttribute(qname, "1");
qname = envelope.createName("UsernameToken", "sse", "http://example.com/user.xsd");
element = envelope.getHeader().addHeaderElement(qname);
element.addTextNode("user1");
qname = envelope.createName("Password");
element = envelope.getHeader().addHeaderElement(qname);
element.addTextNode("1234");
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
This generates the following message:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<S:Header>
<sse:Security xmlns:sse="http://example.com/security.xsd" mustUnderstand="1"/>
<sse:UsernameToken xmlns:sse="http://example.com/user.xsd">user1</sse:UsernameToken>
</S:Header>
<S:Body>
....The rest of the transaction
</S:Body>
</S:Envelope>
The problem is I need to generate a message with the following format:
<soapenv:Envelope 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>
<sse:Security soapenv:mustUnderstand="1" xmlns:sse="http://example.com/security.xsd">
<sse:UsernameToken wsu:Id="UsernameToken-9993341" xmlns:wsu="http://example.com/user.xsd">
<sse:Username>user1</sse:Username>
<sse:Password Type="http://example.com/password#PasswordText">1234</sse:Password>
</sse:UsernameToken>
</sse:Security>
</soapenv:Header>
<soapenv:Body>
....The rest of the transaction
</soapenv:Body>
</soapenv:Envelope>
The "mustUnderstand" attribute doesn't have the soapenv prefix, the sse:Security tag is closed right away instead of having the other tags as children, and the UserName isn't properly formatted as
<sse:Username>user1</sse:Username>
. How can I format the message properly using the SOAPElement methods? The biggest thing I need to know is how to properly next the tags inside of the Security tag and how to have the username/password tags properly formatted.
I've tried different combinations of the addHeaderElement and addChildElement methods, but I can't get it formatted properly and the javadocs don't give enough detail about what they will generate.
This is taken from my working handler. Hope it works for you.
public static final String WSSE_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
public static final String PASSWORD_TEXT_TYPE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText";
public static final String WSSE_SECURITY_LNAME = "Security";
public static final String WSSE_NS_PREFIX = "wsse";
private String username;
private String password;
private boolean mustUnderstand = false;
public boolean handleMessage(SOAPMessageContext messageContext) {
Object bOutbound = messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (bOutbound == Boolean.TRUE) {
try {
if (username != null && username.length() != 0) {
addSecurityHeader(messageContext);
LOG.debug("Added security header");
} else {
LOG.debug("No username configured thus not adding a security header");
}
} catch (Exception e) {
LOG.error("Exception in handleMessage", e);
return false;
}
}
return true;
}
private void addSecurityHeader(SOAPMessageContext messageContext) throws SOAPException {
SOAPFactory sf = SOAPFactory.newInstance();
SOAPHeader header = messageContext.getMessage().getSOAPPart().getEnvelope().getHeader();
if (header == null) {
header = messageContext.getMessage().getSOAPPart().getEnvelope().addHeader();
}
Name securityName = sf.createName(WSSE_SECURITY_LNAME, WSSE_NS_PREFIX, WSSE_NS);
SOAPHeaderElement securityElem = header.addHeaderElement(securityName);
securityElem.setMustUnderstand(mustUnderstand);
Name usernameTokenName = sf.createName("UsernameToken", WSSE_NS_PREFIX, WSSE_NS);
SOAPElement usernameTokenMsgElem = sf.createElement(usernameTokenName);
Name usernameName = sf.createName("Username", WSSE_NS_PREFIX, WSSE_NS);
SOAPElement usernameMsgElem = sf.createElement(usernameName);
usernameMsgElem.addTextNode(username);
usernameTokenMsgElem.addChildElement(usernameMsgElem);
Name passwordName = sf.createName("Type", WSSE_NS_PREFIX, WSSE_NS);
SOAPElement passwordMsgElem = sf.createElement("Password", WSSE_NS_PREFIX, WSSE_NS);
passwordMsgElem.addAttribute(passwordName, PASSWORD_TEXT_TYPE);
passwordMsgElem.addTextNode(password);
usernameTokenMsgElem.addChildElement(passwordMsgElem);
securityElem.addChildElement(usernameTokenMsgElem);
}
Just posting my solution if someone is still wondering --
Name name = soapenv.createName("Security", "sse", "URL");
SOAPHeaderElement security = soapenv.getHeader().addHeaderElement(name);
security.setMustUnderstand(true);
SOAPElement usernameToken = security.addChildElement("UsernameToken", "sse");
SOAPElement username = usernameToken.addChildElement("Username", "sse");
username.addTextNode("TestUser");
SOAPElement password = usernameToken.addChildElement("Password", "sse");
password.addTextNode("TestPassword");
There's enough problems in this code that I'm thinking it's a troll, but heres a start:
The line :
element = envelope.addHeader().addChildElement(qname);
should read:
SOAPHeaderElement secHdrElement = envelope.addHeader().addHeaderElement(qname);
next, instead of:
qname = envelope.createName("mustUnderstand");
element.addAttribute(qname, "1");
probably:
secHdrElement.setMustUnderstand(true);
and
qname = envelope.createName("UsernameToken", "sse", "http://example.com/user.xsd");
element = envelope.getHeader().addHeaderElement(qname);
element.addTextNode("user1");
should be something like:
qname = envelope.createName("UsernameToken", "sse", "http://example.com/user.xsd");
element = secHdrElement.addHeaderElement(
envelope.createName("UsernameToken", "sse", "http://example.com/user.xsd"));
and so on...