Nerea
Nerea

Reputation: 2147

PHP Soap ssl how to trust self-signed certificate

I am making a client in php with soap for a webservice in .net. The webservice run over https with a self-signed certificate and for the tests I must trust this certificate without install it.

The problem is that I allways get this error:

SOAP-ERROR: Parsing WSDL: Couldn't load from 'https://winsystemsintl.com:54904/PSAService.svc?wsdl' : failed to load external entity "https://winsystemsintl.com:54904/PSAService.svc?wsdl".

Here is my code:

$opts = [
        'ssl' => [
            // set some SSL/TLS specific options
            'verify_peer' => false,
            'verify_peer_name' => false,
            'allow_self_signed' => true
        ],
         'http'=>[
            'user_agent' => 'PHPSoapClient'
        ]
    ];

    // Initialize Soap Client
    $this->client = new SoapClient($this->wsdl, array('ssl_method' => SOAP_SSL_METHOD_SSLv3,'soap_version' => SOAP_1_2,  'location' => 'https://winsystemsintl.com:54904/PSAService.svc','stream_context' => stream_context_create($opts), 'exceptions' => true, 'trace' => true));

I was able to get the wsdl with wget:

wget --secure-protocol=SSLv3 https://winsystemsintl.com:54904/PSAService.svc?wsdl --no-check-certificate

Hope someone can help me, thanks a lot.

Upvotes: 2

Views: 6258

Answers (1)

Kris Peeling
Kris Peeling

Reputation: 1025

The problem is that PHP ignores your stream context when downloading the WSDL file. A workaround is to download the WSDL file, and all the schema imports to your local file system (I'm using tidy here to pretty print the XML):

wget --secure-protocol=SSLv3 https://winsystemsintl.com:54904/PSAService.svc?wsdl --no-check-certificate -O - | tidy -xml -indent > PSAService.svc?wsdl
wget --secure-protocol=SSLv3 https://winsystemsintl.com:54904/PSAService.svc?xsd=xsd0 --no-check-certificate -O - | tidy -xml -indent > PSAService.svc?xsd=xsd0
wget --secure-protocol=SSLv3 https://winsystemsintl.com:54904/PSAService.svc?xsd=xsd1 --no-check-certificate -O - | tidy -xml -indent > PSAService.svc?xsd=xsd1
wget --secure-protocol=SSLv3 https://winsystemsintl.com:54904/PSAService.svc?xsd=xsd2 --no-check-certificate -O - | tidy -xml -indent > PSAService.svc?xsd=xsd2
wget --secure-protocol=SSLv3 https://winsystemsintl.com:54904/PSAService.svc?xsd=xsd3 --no-check-certificate -O - | tidy -xml -indent > PSAService.svc?xsd=xsd3

Next, you have to edit PSAService.svc?wsdl (the filename that wget saved to) and change the imports to point to your local system instead of the web. Use the replace-all feature in your favorite editor and replace 'https://winsystemsintl.com:54904/' with '':

Example Before:

<wsdl:types>
  <xsd:schema targetNamespace="http://tempuri.org/Imports">
    <xsd:import schemaLocation="https://winsystemsintl.com:54904/PSAService.svc?xsd=xsd0"
  namespace="http://tempuri.org/" />
    <xsd:import schemaLocation="https://winsystemsintl.com:54904/PSAService.svc?xsd=xsd1"
  namespace="http://schemas.microsoft.com/2003/10/Serialization/" />
    <xsd:import schemaLocation="https://winsystemsintl.com:54904/PSAService.svc?xsd=xsd2"
  namespace="http://schemas.datacontract.org/2004/07/PSA.Service.MessageObjects.Pregunta" />
    <xsd:import schemaLocation="https://winsystemsintl.com:54904/PSAService.svc?xsd=xsd3"
  namespace="http://schemas.datacontract.org/2004/07/PSA.Service.MessageObjects.Respuesta" />
  </xsd:schema>
</wsdl:types>

After:

<wsdl:types>
  <xsd:schema targetNamespace="http://tempuri.org/Imports">
    <xsd:import schemaLocation="PSAService.svc?xsd=xsd0"
  namespace="http://tempuri.org/" />
    <xsd:import schemaLocation="PSAService.svc?xsd=xsd1"
  namespace="http://schemas.microsoft.com/2003/10/Serialization/" />
    <xsd:import schemaLocation="PSAService.svc?xsd=xsd2"
  namespace="http://schemas.datacontract.org/2004/07/PSA.Service.MessageObjects.Pregunta" />
    <xsd:import schemaLocation="PSAService.svc?xsd=xsd3"
  namespace="http://schemas.datacontract.org/2004/07/PSA.Service.MessageObjects.Respuesta" />
  </xsd:schema>
</wsdl:types>

Repeat for each of the files that were downloaded.

Next, change your code to the following (I assume here that all PHP/WSDL files are in the same folder):

$opts = [
'ssl' => [
  // set some SSL/TLS specific options
  'verify_peer' => false,
  'verify_peer_name' => false,
  'allow_self_signed' => true
],
  'http'=>[
    'user_agent' => 'PHPSoapClient'
  ]
];

// Initialize Soap Client
$client = new SoapClient('PSAService.svc?wsdl', array('ssl_method' => SOAP_SSL_METHOD_SSLv3,'soap_version' => SOAP_1_2,  'location' => 'https://winsystemsintl.com:54904/PSAService.svc','stream_context' => stream_context_create($opts), 'exceptions' => true, 'trace' => true));
var_dump($client->__getFunctions());

Now the SoapClient has skipped downloading the WSDL from the web, and you're ready to start making calls using your stream context.

Upvotes: 1

Related Questions