Correct WS-Policy for UsernameToken and CXF SOAP WS - cxf

I have following annotation on my SOAP Web Service:
#Policy(uri = "classpath:/ws/soap/UsernameTokenPolicy.xml")
and such Endpoint configuration:
Map<String, Object> inProps = new HashMap<>();
inProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
inProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
WSS4JInInterceptor wssIn = new WSS4JInInterceptor(inProps);
endpoint.getInInterceptors().add(wssIn);
endpoint.getProperties().put(SecurityConstants.USERNAME_TOKEN_VALIDATOR, authenticationPlugin);
This is the the content of UsernameTokenPolicy.xml:
<?xml version="1.0" encoding="UTF-8"?>
<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<sp:SupportingTokens>
<wsp:Policy>
<sp:UsernameToken/>
</wsp:Policy>
</sp:SupportingTokens>
</wsp:Policy>
The client sends such security header:
<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-FA33408419A5268E38151818972919430">
<wsse:Username>USERABC</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">123456789</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
and CXF Server rejects the policy:
org.apache.cxf.ws.policy.PolicyException: These policy alternatives can not be satisfied:
{http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702}SupportingTokens
{http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702}UsernameToken
at org.apache.cxf.ws.policy.AssertionInfoMap.checkEffectivePolicy(AssertionInfoMap.java:179)
I'm not sure what is wrong here. According to this document my policy looks all right (sp:IncludeToken does not change anything).
Any help is appreciated.

I've found the problem, I need Policy Aware Interceptor as first one:
PolicyBasedWSS4JInInterceptor pwssIn = new PolicyBasedWSS4JInInterceptor();
endpoint.getInInterceptors().add(pwssIn);
Map<String, Object> inProps = new HashMap<>();
inProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
inProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
WSS4JInInterceptor wssIn = new WSS4JInInterceptor(inProps);
endpoint.getInInterceptors().add(wssIn);
endpoint.getProperties().put(SecurityConstants.USERNAME_TOKEN_VALIDATOR, authenticationPlugin);

Related

Encrypting username token with apache cxf

Greetings good people.
I have a soap web service that I want to consume.I have created a small project to simulate what is required in the actual project especially on the username token encryption.
There are steps provided on how to encrypt the password on the client side as listed below:
Write the unencrypted password value.
Then, encrypt the block of data created in step 1 with the public portion of the password key certificate. Use the RSA algorithm, and use PKCS #1.5 padding (not OAEP), and add the result to the encrypted stream – this becomes the encrypted password which is submitted via the API.
Convert the resulting encrypted byte array into a string using base64 encoding. Present this base64 encoded string in the API request as the initiator SecurityCredential value.
Password to be encrypted with a public key from an X509 certificate issued to the Initiator specifically for this purpose.
So far I have been able to create a client and the server and I'm able to send a request and get a response.
I'm also able to secure the web service by passing a username token with password as plain text in the ClientPasswordCallback class and checking these credentails in the ServerPasswordCallback class.
I have gone further and in a seperate request encrypted the body part of the message using wss4j, RSA, X509 whereby I have public key stored in the clientKey.jks and a private key stored in privateKey.jks and by providing appropriate passwords in client and server password call back handlers I have been able to encrypt the body part at the client and decrypt it at the server.
The Challenge: The main challenge I'm experiencing is combining the two steps above in a single request such that using the public key, I'm able to encrypt the password in the username token and decrypt the same at the server side using the private key.
NB I have generated the keys for testing using keygen tool that comes with the jdk.
I'm imagining that there will be two passwords in the ClientPasswordCallback class, one for the clientKey.jks keystore and the other other password that needs to be encrypted.
This is what I have been able to archive so far:
Client side
TestMathUtility class
public static void main(String[] args) {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
// Use the URL defined in the soap address portion of the WSDL
factory.setAddress("http://localhost:8080/MathUtility/services/MathUtilityPort");
// Utilize the class which was auto-generated by Apache CXF wsdl2java
factory.setServiceClass(MathUtility.class);
Object client = factory.create();
// Adding Logging Interceptors
LoggingOutInterceptor loggingOutInterceptor = new LoggingOutInterceptor();
loggingOutInterceptor.setPrettyLogging(true);
ClientProxy.getClient(client).getOutInterceptors().add(loggingOutInterceptor);
LoggingInInterceptor loggingInInterceptor = new LoggingInInterceptor();
loggingInInterceptor.setPrettyLogging(true);
ClientProxy.getClient(client).getInInterceptors().add(loggingInInterceptor);
// Set up WS-Security Encryption
// Reference: https://ws.apache.org/wss4j/using.html
Map<String, Object> props = new HashMap<String, Object>();
props.put(WSHandlerConstants.USER, "testkey");
props.put(WSHandlerConstants.ACTION, WSHandlerConstants.ENCRYPT);
props.put(WSHandlerConstants.PASSWORD_TYPE, "PasswordText");
props.put(WSHandlerConstants.ENC_PROP_FILE, "clientKeystore.properties");
props.put(WSHandlerConstants.ENCRYPTION_PARTS, "{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body");
props.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordCallback.class.getName());
WSS4JOutInterceptor wss4jOut = new WSS4JOutInterceptor(props);
ClientProxy.getClient(client).getOutInterceptors().add(wss4jOut);
try {
// Call the Web Service to perform an operation
int response = ((MathUtility)client).addIntegers(5, 10);
System.out.println("Response we've got ========= "+response);
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
ClientPasswordCallback class
public class ClientPasswordCallback implements CallbackHandler {
#Override
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
// set the password for our message.
pc.setPassword("clientstorepass");
}
}
Server side
MathUtility class
#WebService(targetNamespace = "http://utility.math.com/", portName = "MathUtilityPort", serviceName = "MathUtilityService")
public class MathUtility {
public int addIntegers(int firstNum, int secondNum) {
return firstNum + secondNum;
}
public int factorial(int n) {
int result = 1;
for (int i = 1; i <= n; i++) {
result = result * i;
}
return result;
}
}
ServerPasswordCallback class
public class ServerPasswordCallback implements CallbackHandler {
#Override
public void handle(Callback[] arg0) throws IOException,
UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) arg0[0];
// set the password for our message.
pc.setPassword("storepass");
}
}
cxf-beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<bean id="myPasswordCallback" class="com.math.utility.security.ServerPasswordCallback"/>
<jaxws:endpoint xmlns:tns="http://utility.math.com/" id="mathutility"
implementor="com.math.utility.MathUtility" wsdlLocation="wsdl/mathutility.wsdl"
endpointName="tns:MathUtilityPort" serviceName="tns:MathUtilityService"
address="/MathUtilityPort">
<jaxws:features>
<bean class="org.apache.cxf.feature.LoggingFeature" />
</jaxws:features>
<jaxws:inInterceptors>
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key="user" value="testkey"/>
<entry key="action" value="Encrypt"/>
<entry key="passwordType" value="PasswordText"/>
<entry key="decryptionParts" value="{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body"/>
<entry key="decryptionPropFile" value="serverKeystore.properties"/>
<entry key="passwordCallbackRef">
<ref bean="myPasswordCallback"/>
</entry>
</map>
</constructor-arg>
</bean>
</jaxws:inInterceptors>
</jaxws:endpoint>
clientKeyStore.properties file the same structure is used on the server side
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.file=clientkeystore.jks
org.apache.ws.security.crypto.merlin.keystore.password=clientstorepass
org.apache.ws.security.crypto.merlin.keystore.type=jks
The .jks files used have not been provided
NB I'm not using spring.
If you want to have a custom digest you could override the method verifyCustomPassword(UsernameToken usernameToken,
RequestData data) in UsernameTokenValidator
To hook it up to your webservice have a look at my answer to another SO-question. The essentials of this answers are:
<property name="wssConfig">
<ref bean="usernameTokenWssConfig"/>
</property>
And add the referenced class to your codebase:
#Component("usernameTokenWssConfig")
public class UsernameTokenWssConfig extends WSSConfig {
public UsernameTokenWssConfig() {
setValidator(WSSecurityEngine.USERNAME_TOKEN, new CustomUsernameTokenValidator());
setRequiredPasswordType(WSConstants.CUSTOM_TOKEN );
}
}
This is how I did the encryption Of UT using encryption parts
outProps.put(
WSHandlerConstants.ENCRYPTION_PARTS,
"{Content}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}UsernameToken"
);
In order to encrypt the username token with the encryption parts . Add the SOAP header namespace inside the second curly braces
I got an encrypted UT like below(I only encrypted the content only you can do the element if you want)
<wsse:UsernameToken wsu:Id="UsernameToken-99bea96d-c6ef-444c-aa8a-ec807f58aa0c">
<xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="ED-59f84d2b-3195-436f-b8f4-513fea23c00a" Type="http://www.w3.org/2001/04/xmlenc#Content">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc" />
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<wsse:SecurityTokenReference xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey">
<wsse:Reference URI="#EK-748c3d27-f6be-4b81-b864-87bc6457e247" />
</wsse:SecurityTokenReference>
</ds:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>wSZsu9LR6q9fpUPYYF5GSA7T/3iZWMd0cB/80Z33DThzCB0kqnupGETVmGfVQheGUc3O+/B4X7i70aMTyOo5u0fIqa4kwrlKZBe9he359mpgakKgC4wOb65sDThT1fH4PvY6TSBjIOJ0T5jIyt1pGwacRLzmvFxxHxr3qfAOf27LLGJ0P0eAKchE19nAkfP+Tc2GbAkcxi/4SDQ7bBWVaveRgSET0dpheooBGORtt4VJ/dyMwogupAyJKoiqe3RFRCvsmK/UtkVGQYh/W14ei/s7G3mVAch8fQZXCS8jcEaqzkDaNzrZo8+IjJFgrPQY23g3fp57QXIDB84NNUhsm7NHXMNfAq7x97kng+Qwke6uqHcMPjGI9boKw/wZmhipYstFzUpOpF86W9FwcJPyTFR58jvdnX5OGJ1wFbFdI9cAjWdncIEmnOTl69pKRmGmbJYj7Ie43q+eNH/1+2RawBRhZG43VLZL5C7ydFu0xJ2DsD4nacvDfH0i8tcMCHyHkWf2po9Y/dBtS2kWAxfNxWQNvI1BceumsMvpSzK7WjXPJ/vaKlMoSQJtsBxg9RhA
</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData>
</wsse:UsernameToken>

SoapFault MustUnderstand headers, CXF WSS4J No crypto property file supplied

My SOAP server is receiving a SOAP message with must understand headers set to 1.
In order to understand the header I am using a wss4j interceptor.
My sign.properties file is:
org.apache.ws.security.crypto.provider=org.apache.wss4j.common.crypto.Merlin
org.apache.ws.security.crypto.merlin.truststore.type=jks
org.apache.ws.security.crypto.merlin.truststore.password=changeit
org.apache.ws.security.crypto.merlin.truststore.file=keystore/truststore.jks
My Endpoint xml:
<jaxws:inInterceptors>
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key="action" value="Timestamp Signature"/>
<entry key="signaturePropFile" value="XXXXXX/WEB-INF/classes/etc/sign.properties"/>
<entry key="passwordCallbackClass" value="XX.XX.XX.XXXXXX.lifecycleapp.UTPasswordCallback"/>
</map>
</constructor-arg>
</bean>
</jaxws:inInterceptors>
However I am getting the error "org.apache.wss4j.common.ext.WSSecurityException: No crypto property file supplied to verify signature"
I am assuming it is something as simple as not correctly addressing the signaturePropFile but I have tried giving the full file path but that has returned the same result.
Any help would be greatly appreciated.
Start by enabling DEBUG/FINE logging. It will tell you exactly what the problem is....likely that it can't load the path you have given. I would suggest trying the following instead:
<entry key="signaturePropFile" value="classes/etc/sign.properties"/>
Colm.
This happened to me because I tried to use a HashMap instead of a Properties map.
That is, instead of the following
Map<String, Object> outProps = new HashMap<>(7);
outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE);
outProps.put(WSHandlerConstants.USER, CLIENT_SSL_CERT_ALIAS);
outProps.put(WSHandlerConstants.PW_CALLBACK_REF, new ClientPasswordCallback(privateKeyPassword));
outProps.put(WSHandlerConstants.SIG_KEY_ID, "DirectReference");
outProps.put(WSHandlerConstants.SIGNATURE_PARTS, "{Element}{" + "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" + "}Timestamp");
Properties signingCryptProperties = new Properties();
// Reference: http://camel.465427.n5.nabble.com/Dynamically-set-WSS4J-interceptor-properties-td5551391.html
signingCryptProperties.put("org.apache.ws.security.crypto.provider", "org.apache.ws.security.components.crypto.Merlin");
signingCryptProperties.put("org.apache.ws.security.crypto.merlin.keystore.password", keystorePassword);
signingCryptProperties.put("org.apache.ws.security.crypto.merlin.keystore.file", "client.jks");
signingCryptProperties.put("org.apache.ws.security.crypto.merlin.keystore.type", "JKS");
outProps.put(SIG_PROP_REF_ID, signingCryptProperties);
outProps.put(WSHandlerConstants.SIG_PROP_REF_ID, SIG_PROP_REF_ID);
WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
I had tried to make the signingCryptProperties a HashMap
like this
Map<String, String> signingCryptProperties = new HashMap<String, String>()
and that caused the WSSecurityEngine: No crypto property file supplied to verify signature WSSEcurityException

Silverlight File upload to the remote server error

I need to upload a file to the remote server in silverlight project.
Following is my code. I want to upload a PDF file.
public bool UploadHelpDocument(string FileName, byte[] ms)
{
if (FileName != null)
{
if (ms.Length > 0)
{
FileUpload fu = new FileUpload();
string HelpDocPath = ConfigurationManager.AppSettings["HelpDocs"];
if (!Directory.Exists(HelpDocPath))
{
Directory.CreateDirectory(HelpDocPath);
}
if(fu.saveFileChunk(FileName, ms, HelpDocPath, 0) == true)
{
string fileURL = ConfigurationManager.AppSettings["HelpDocs"] + FileName;
byte[] localHelpfile = readLocalShapeFile(fileURL);
string sURL = "http://serverpath";
WebRequest request = WebRequest.Create(sURL);
request.ContentType = "application/ms-word";
request.Method = "PUT";
request.Credentials = new NetworkCredential("", "");
Stream requestStream = request.GetRequestStream();
requestStream.Write(localHelpfile, 0, localHelpfile.Length);
requestStream.Close();
WebResponse response = request.GetResponse();
return false;
}
}
}
return false;
}
I am getting an error at
WebResponse response = request.GetResponse();
this line. It say The remote server returned an error: (405) Method Not Allowed.
What might be the reason of this error?
Thank you
Do you want send WebRequest from Silverlight app?
If no, I think that destination server can't handle this request method or type of file. You can try change ContentType like:
this:
request.ContentType = "text/msword";
or
request.ContentType = "text/plain";
If this not help, I think that server does not handle PUT method, You need to research configuration of destination server.
If yes, it is look like crossdomain issue. You can use one of two approaches.
1) If you have access to destination server, You can create crossdomain.xml or/and clientaccesspolicy.xml on them like this:
clientaccesspolicy.xml
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*">
<domain uri="*"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
crossdomain.xml
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-http-request-headers-from domain="*" headers="*"/>
</cross-domain-policy>
You can read more:
https://msdn.microsoft.com/en-us/library/cc197955%28VS.95%29.aspx
http://www.leggetter.co.uk/2008/10/24/how-to-make-a-cross-domain-web-request-with-silverlight-2.html
2) If You have not access to destination server (worse news). You need to create WebRequest bypass local serwer. The best approach is by integrate Silverlight with WCF RIA Service. At first you need to send file by RIA Service to local server and next from server you need to send WebRequest with this file to destination server unlimited.
public void RIAHandleFile(byte[] file)
{
//(...)
requestStream.Write(file, 0, file.Length);
//(...)
}
In Silverlight invoke this function like
byte[] file;
InvokeOperation ria = domainContext.RIAHandleFile(file)

Configuring WSS4J with CXF

I was doing pretty well with setting up a contract first set of web services using CXF until I started adding in the WSS4J piece.
I'm trying to debug sending a password and login in the soap header. I am getting null when I call getPassword() in the WSPasswordCallback class. I can see from the soap envelope that a password was sent.
This post, http://old.nabble.com/PasswordDigest-and-PasswordText-difference-td24475866.html, from 2009, made me wonder if I am missing (need to create) a UsernameTokenHandler.
And if that is true, can someone point me to how I would configure it in the spring/cxf bean xml file?
Any advice or suggestions would be appreciated.
Here's the Java file in question:
package com.netcentric.security.handlers;
import java.io.IOException;
import javax.annotation.Resource;
import javax.com.urity.auth.callback.Callback;
import javax.com.urity.auth.callback.CallbackHandler;
import javax.com.urity.auth.callback.UnsupportedCallbackException;
import org.apache.ws.com.urity.WSPasswordCallback;
public class ServicePWCallback implements CallbackHandler
{
#Override
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
try {
for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof WSPasswordCallback) {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
sString login = pc.getIdentifier();
String password = pc.getPassword();
// password is null, not the expected myPASSWORD**1234
int n = pc.getUsage();
// this is 2 == WSPasswordCallback.USERNAME_TOKEN
//...
The CXF/Spring configuration file:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"
default-dependency-check="none" default-lazy-init="false">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<bean id="serverPasswordCallback" class="com.netcentric.security.handlers.ServicePWCallback"/>
<bean id="wss4jInInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken"/>
<entry key="passwordType" value="PasswordText"/>
<entry key="passwordCallbackRef">
<ref bean="serverPasswordCallback"/>
</entry>
</map>
</constructor-arg>
</bean>
<jaxws:endpoint id="FederationImpl"
implementor="com.netcentric.services.federation.FederationImpl"
endpointName="e:federation"
serviceName="e:federation"
address="federation"
xmlns:e="urn:federation.services.netcentric.sec">
<jaxws:inInterceptors>
<bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>
<ref bean="wss4jInInterceptor"/>
</jaxws:inInterceptors>
</jaxws:endpoint>
</beans
The soap message:
<?xml version="1.0" encoding="UTF-8"?>
<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>
<wsse:comurity xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wscomurity-comext-1.0.xsd" soapenv:mustUnderstand="1">
<wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wscomurity-utility-1.0.xsd" wsu:Id="Timestamp-16757598">
<wsu:Created>2011-09-22T18:21:23.345Z</wsu:Created>
<wsu:Expires>2011-09-22T18:26:23.345Z</wsu:Expires>
</wsu:Timestamp>
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wscomurity-utility-1.0.xsd" wsu:Id="UsernameToken-16649441">
<wsse:Username>pam</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">myPASSWORD**1234</wsse:Password>
</wsse:UsernameToken>
</wsse:comurity>
</soapenv:Header>
<soapenv:Body>
<getVersion xmlns="urn:federation.services.netcentric.com">
<getVersionRequest/>
</getVersion>
</soapenv:Body>
</soapenv:Envelope>
If using CXF 2.4.x, I would recommend reading:
http://coheigea.blogspot.com/2011/02/usernametoken-processing-changes-in.html
and seeing if that helps provide some extra information. Colm's blog is a treasure trove of useful info about recent WSS4J releases.
Thanks for all your help. I have made progress on this. I am using CXF 2.4.2 and WSS4J 1.6.2. The framework now takes care of checking the password for you. So the correct inside section is
if (callbacks[i] instanceof WSPasswordCallback) {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
sString login = pc.getIdentifier();
String password = getPassword(login);
pc.getPassword(login);
//...
}
Instead of retrieving the password from the soap header to compare against the expected value, you lookup the expected value and pass it to the framework to do the comparison.
I add this :
// set the password on the callback.
This will be compared to the
// password which was sent from the client.
pc.setPassword("password");
==> the password between "" will be compared with password sended by client.
Client side: write login = bob ; Password = bobPassword (will be digested)
Server side: Catch user = bob and the function user.setPassword(bobPassword) verify if the password received is correct or no.

Getting ParsingError, InvalidSoapActionHeader on SQL Server SOAP request

I am attempting to send a SOAP request to SQL Server 2005, but I am getting a vague error in response. Can anyone interpret for me?
Here is my request (linebreaks have been added for readability):
<v:Envelope
xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns:d="http://www.w3.org/2001/XMLSchema"
xmlns:c="http://www.w3.org/2001/12/soap-encoding"
xmlns:v="http://www.w3.org/2001/12/soap-envelope">
<v:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>cgtyoder</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">SooperSekrit</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</v:Header>
<v:Body>
<MyFunction xmlns="http://tempuri.org/" id="o0" c:root="1">
<OutputParam i:nil="true" />
</MyFunction>
</v:Body>
</v:Envelope>
And here is the XML response (linebreaks added):
<?xml version="1.0" encoding="utf-8"?>
<SOAP-ENV:Envelope xml:space="preserve"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:sql="http://schemas.microsoft.com/sqlserver/2004/SOAP"
xmlns:sqlsoaptypes="http://schemas.microsoft.com/sqlserver/2004/SOAP/types"
xmlns:sqlrowcount="http://schemas.microsoft.com/sqlserver/2004/SOAP/types/SqlRowCount"
xmlns:sqlmessage="http://schemas.microsoft.com/sqlserver/2004/SOAP/types/SqlMessage"
xmlns:sqlresultstream="http://schemas.microsoft.com/sqlserver/2004/SOAP/types/SqlResultStream"
xmlns:sqltransaction="http://schemas.microsoft.com/sqlserver/2004/SOAP/types/SqlTransaction"
xmlns:sqltypes="http://schemas.microsoft.com/sqlserver/2004/sqltypes"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<SOAP-ENV:Body>
<SOAP-ENV:Fault xmlns:sqlsoapfaultcode="http://schemas.microsoft.com/sqlserver/2004/SOAP/SqlSoapFaultCode">
<faultcode>SOAP-ENV:Client</faultcode>
<faultstring>There was an error in the incoming SOAP request packet: Client, ParsingError, InvalidSoapActionHeader</faultstring>
<faultactor>http://schemas.microsoft.com/sqlserver/2004/SOAP</faultactor>
<detail xmlns:SOAP-1_2-ENV="http://www.w3.org/2003/05/soap-envelope">
<SOAP-1_2-ENV:Code>
<SOAP-1_2-ENV:Value>SOAP-1_2-ENV:Sender</SOAP-1_2-ENV:Value>
<SOAP-1_2-ENV:Subcode>
<SOAP-1_2-ENV:Value>sqlsoapfaultcode:ParsingError</SOAP-1_2-ENV:Value>
<SOAP-1_2-ENV:Subcode>
<SOAP-1_2-ENV:Value>sqlsoapfaultcode:InvalidSoapActionHeader</SOAP-1_2-ENV:Value>
</SOAP-1_2-ENV:Subcode>
</SOAP-1_2-ENV:Subcode>
</SOAP-1_2-ENV:Code>
<SOAP-1_2-ENV:Reason>
<SOAP-1_2-ENV:Text xml:lang="en-US">There was an error in the incoming SOAP request packet: Sender, ParsingError, InvalidSoapActionHeader</SOAP-1_2-ENV:Text>
</SOAP-1_2-ENV:Reason>
<SOAP-1_2-ENV:Node>https://10.199.5.116:444/dt2</SOAP-1_2-ENV:Node>
<SOAP-1_2-ENV:Role>http://schemas.microsoft.com/sqlserver/2004/SOAP</SOAP-1_2-ENV:Role>
<SOAP-1_2-ENV:Detail/>
</detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Here is my SOAP Endpoint definition on the server:
CREATE ENDPOINT [DroidTest2]
AUTHORIZATION [cgtyoder]
STATE=STARTED
AS HTTP (PATH=N'/dt2', PORTS = (SSL), AUTHENTICATION = (BASIC), SITE=N'*', SSL_PORT = 444, COMPRESSION=DISABLED)
FOR SOAP (
WEBMETHOD 'DroidFunction'( NAME=N'[pubs].[dbo].[DroidFunction]'
, SCHEMA=DEFAULT
, FORMAT=ROWSETS_ONLY), LOGIN_TYPE=MIXED, BATCHES=DISABLED, WSDL=N'[master].[sys].[sp_http_generate_wsdl_defaultsimpleorcomplex]'
, SESSIONS=ENABLED, SESSION_TIMEOUT=600, DATABASE=N'pubs', NAMESPACE=N'http://tempuri.org/', SCHEMA=STANDARD
, CHARACTER_SET=XML)
GO
The UDF DroidFunction takes no arguments and returns a string (VarChar(30)). I am able to connect to https://10.199.5.116/dt2?wsdl and get the WSDL. Thanks for any pointers here.
See http://social.msdn.microsoft.com/Forums/en-US/sqldataaccess/thread/7619d2e0-a5eb-4379-b027-234103e7f171 for my solution.

Resources