phpwso2rampartusernametokenwsh

WS02 / WSF PHP 2.1.0 UsernameToken issues


i try to call a partner WS using usernameToken. I use for that ws02 wsf_2.0.0 under php5.2.x and it rocks. Now we want's to migrate on a different solution based on php5.3, fortunately ws02 provide a 2.1.0 tag compatible with php5.3. I take the time to read the new features and documentation of this new release and especially regarding the usernameToken. I understood this release use signing regarding the usernameToken through a cert and private key. I guess b/c of the AsymetricTransportBinding policy. In my case i didn't want to sign anything through certificate or whatever. I read also that ws02 provide a kind of fallback in a separate xml file to avoid any signing.

After reading many posts, forums i need some help from the community b/c i'm totally stuck.

Here's the code used to request the WS in php5.3 - wsf 2.1.0 ( using HTTP )

$policy   = new \WSPolicy( $policy ); ( $policy is the one from the call_back folder with a file_get_contents() )

$security = new \WSSecurityToken( array(
  'user'                    => 'my_username',
  'password'                => 'my_password',
  'passwordType'            => 'Digest',
  'ttl'                     => '300'
));

$this->oSoapClient = new \WSClient( array(
  wsdl:          http://www.xxx.xx/comparatorservices/CalculationService?WSDL
  to:            http://www.xxx.xx/comparatorservices/CalculationService
  useWSA:        true
  useSOAP:       1.1,
  policy:        $policy,
  securityToken: $security
));

$proxy = $this->oSoapClient->getProxy();
$response = $proxy->wykonajKalkulacje( $MySuperRequestObject );

At this step :

  1. I activated the debug traces ( log level 4 )
  2. I confirm that my "to" is using http accoring to the wsdl definition

    wsdl:port name="CalculationServiceHttpPort" binding="tns:CalculationServiceHttpBinding" wsdlsoap:address location="http://www.xxxx.xx/comparatorservices/CalculationService" /wsdl:port

Now from the debug logs i catch this :

[Wed Jul 25 05:22:53 2012] [error] rampart_in_handler.c(91) [rampart]SOAP header cannot be found.
[Wed Jul 25 05:22:53 2012] [error] phase.c(224) Handler RampartInHandler invoke failed within phase Security
[Wed Jul 25 05:22:53 2012] [error] engine.c(657) Invoking phase Security failed
[Wed Jul 25 05:22:53 2012] [error] engine.c(262) Invoking operation specific phases failed for operation __OPERATION_OUT_IN__
[Wed Jul 25 05:22:53 2012] [error] /home/agruet/08_KRK_sources/wso2-wsf-php-src-2.1.0/src/wsf_wsdl.c(1226)      [wsf_wsdl] Response envelope not found

So my first idea was to sniff the traffic and especially the SOAP Header between the working ( wsf_2.0.0 / php5.2.x ) and the breaked ( wsf_2.1.0 / php5.3 )

Here's the 2.0.0 ( working )

    <soapenv:Envelope 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" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">

        <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
            <wsse:Username>my_username</wsse:Username>

            <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">
              hashed(my_password)
            </wsse:Password>

            <wsse:Nonce>hashed</wsse:Nonce>
            <wsu:Created>2012-07-26T20:40:26.991Z</wsu:Created>

        </wsse:UsernameToken>
    </wsse:Security>
</soapenv:Header>

And the 2.1.0 ( not working / breaked )

         <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
       <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">

        <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">

            <wsse:Username>my_username</wsse:Username>
            <wsse:Password
                Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">hashed(my_password)</wsse:Password>
            <wsse:Nonce>hashed</wsse:Nonce>
            <wsu:Created>2012-07-25T00:44:56.758Z</wsu:Created>
        </wsse:UsernameToken>
    </wsse:Security>
</soapenv:Header>

As u can see the only difference come from the wsse:Security namespace. ( missing xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/ )

And that's all ...

Inspecting the rampart_in_handler.c at line 91 according to the debug log said :

soap_header = axiom_soap_envelope_get_header(soap_envelope, env);
    if(!soap_header)
    {
        /*No SOAP header, so no point of proceeding. FAIL*/
        AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "[rampart]SOAP header cannot be found.");
        return AXIS2_FAILURE;
    }

Meaning yeah.... the soap_header is false.. but why? Is there any smart guy in order to explain what's wrong ?

nota 1: I inspected the policy sent to the partner WS from the working ( 2.0.0 ) it seem's a AsymetricBinding is used... wich is weird as long in the 2.0.0 we didn't provide any cert or keys.

nota 2: I also tried to use signed username token with the classic WSPolicy Object array params - I created a x509 cert and privatekey then use the functions to load these files and use the array params to load it into the WSSecurity Constructor... but i receive the same error / Sniffing is a pain b/c the datas are crypted or something like that ( wich seem's to be normal in this way )

nota 3: Currently tested on Ubuntu10.04-3LTS with the pre-compiled php packges from apt-get

PLZ HELP !


Solution

  • I finally found the issue and i fixed the rampart_in_handler.c:91

    The issue was coming from the response and not from the request... I Inspected through a tcp sniffer and the response from the partner WS was made without any soap:Header.

    Compliant or not with standards, with the last release ( 2.0.0 ) it was working. So i decided to tweak a little bit the code in rampart_in_handler.c file to return a success in the case of soap header is missing...

    In my opinion and PLZ correct me if I'm wrong :

    The test on the soapHeader response was added certainly b/c of the asymetricBinding transport and the new signed usernametoken case. However, if we want to use usernametoken without signing ( through the basic policy.xml ) AND the response is made without any soap:Header ; then rampart will always return a failure...

    Also, i analysed the php code under the scripts/ folder regarding the way wsf handle the response and i saw on this file : wsf_wsdl.php under the function wsf_process_response() :

    if($response_header_string && !empty($response_header_string)) {
        $header_dom = new DomDocument();
        $header_dom->preserveWhiteSpace = FALSE;
        $header_dom->loadXML($response_header_string);
    }
    

    Meaning on the php side, when the data are received, wsf/php assume a case without any soapHeader... ( there is no failure if the soapHeader is missing ) Super weird !?

    At last but not least, i found a weird bug on both wsf_wsdl_serialization.php and wsf_wsdl_deserialization.php files.

    For instance if you plan to send and/or receive params/values with a string like that :

                                "110% Sigma of something" 
    

    It will fail and create a segfault during serialize/unserialize process !

    Now i'm wondering myself why ? But at a first view, for sure, "110% Sig.." contain "% S" and it's pretty closed of "%s"...

    I think this bug is this one mentioned here :

    http://old.nabble.com/WSF-PHP-server-segfault-on-wsf_wsdl_serialization.php---td24329956.html

    If i change the S by D or anything else it works...

    What a pain...