WS-Security bağlama PHP ile Web hizmeti korumalı

5 Cevap php

Ben parola korumalı bir Web hizmetine bağlanmaya çalışıyorum ve url https olduğunu. Ben komut bir istekte önce kimlik doğrulaması için nasıl anlamaya olamaz. Kısa sürede ben hizmeti tanımlamak gibi bir istekte gibi görünüyor. Örneğin, ben koyarsanız:

$client = new SoapClient("https://example.com/WSDL/nameofservice",
       array('trace' => 1,)
);

ve sonra tarayıcıda sitesine gidin, ben alıyorum:

Fatal error: Uncaught SoapFault exception: 
[WSDL] SOAP-ERROR: Parsing WSDL: Couldn't load from
'https://example.com/WSDL/nameofservice' in /path/to/my/script/myscript.php:2 
Stack trace: #0 /path/to/my/script/myscript.php(2): 
SoapClient->SoapClient('https://example...', Array) #1 {main} thrown in 
/path/to/my/script/myscript.php on line 2

Ben bir Sabun Server olarak hizmet tanımlayan denerseniz, gibi:

$server= new SoapServer("https://example.com/WSDL/nameofservice");

Alıyorum:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>WSDL</faultcode>
<faultstring>
SOAP-ERROR: Parsing WSDL: 
Couldn't load from 'https://example.com/WSDL/nameofservice'
</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Ben sunucu döndürür görmek için henüz ham bir istek zarfı göndererek denemedim, ama bu geçici bir çözüm olabilir. Ama kimse ben yerleşik sınıfların php kullanarak kurmak nasıl söyle umuyordum. Ben diziye "kullanıcı adı" ve "parola" ekleyerek denedim, ama bu iyi oldu. Sorun ben bile isteği reddediyor olmadığını ben hiç uzak bir site kuruyorum olmadığını söylemek şöyle dursun, değil ki.

5 Cevap

Sorun WSDL belge şekilde korunduğunu gibi görünüyor (temel kimlik doğrulaması - SoapClient ile desteklenen Bunu özet kimlik doğrulaması thinkg yok, bu yüzden bu durumda şans olurdu) ve SoapClient, bu nedenle okuma ve hizmet açıklamasını ayrıştırmak olamaz.

Her şeyden önce size bir kimlik doğrulama iletişim kutusunu sunulan konum olmadığını kontrol etmek tarayıcınızda WSDL yer açmak için çalışmalısınız. Bir kimlik doğrulama iletişim var ise SoapClient WSDL belgesi almak üzerine gerekli oturum açma kimlik bilgilerini kullanan emin olmalısınız. Sorun kullanırken SoapClient, sadece login ve password seçenek (yanı sıra local_cert ile tanımlanan kimlik bilgilerini gönderir olmasıdır WSDL alınırken, hizmet değil baþlatýrken müşteri oluşturma konusunda sertifika kimlik doğrulaması)) (here. Bu sorunun üstesinden gelmek için iki yöntem vardır:

  1. SoapClient yapıcı çağrısı WSDL url oturum açma kimlik bilgilerini ekle

    $client = new SoapClient(
        'https://' . urlencode($login) . ':' . urlencode($password) . '@example.com/WSDL/nameofservice',
        array(
            'login' => $login,
            'password' => $password
        )
    );
    

    Bu çok basit bir çözüm olmalı - ama PHP Bug #27777 bu ya (ben denemedim) bu iş olmaz yazılıdır.

  2. El ile wget, örneğin SoapClient diskte saklamak ve örneğini HTTP akışı sarıcı veya ext/curl kullanarak veya el ile tarayıcınız üzerinden veya aracılığıyla WSDL getir Yerel WSDL başvuru.

    Eğer değişikliği algılar ve disk üzerinde yeni sürümü saklamak zorunda gibi WSDL belgesi değiştirirse Bu çözüm sorunlu olabilir.

Hiçbir kimlik doğrulama iletişim gösterilir ve tarayıcınızda WSDL okuyabilir eğer, olası diğer hatalar / sorunlar için kontrol etmek için biraz daha ayrıntı olursa.

SoapClient hizmet kendisi için çağrıda önce hizmet descripion belgeyi okumaya zaten şoklar gibi bu sorun kesin hizmet kendisi ile ilgili değildir.

EDIT:

Yerel WSDL dosyası olması bir ilk adım - bu SoapClient hizmeti ile iletişim kurmak için nasıl bilmek sağlayacaktır. WSDL doğrudan başka bir sunucudan, hizmet yerden servis edilir ya da yerel bir dosyadan okunan ise fark etmez - hizmet adresler yani SoapClient her yerde hizmet için bakmak bilen WSDL içinde kodlanmıştır nokta.

İkinci sorun artık SoapClient Eğer SoapClient belirli başlıklarını ele genişletmek gerektiği anlamına gelir, özgün WS-Security özellikler için destek olmasıdır. Gerekli davranış eklemek için bir uzantısı noktası SoapClient::__doRequest() which pre-processes the XML payload before sending it to the service endpoint. But I think that implementing the WS-Security solution yourself will require a decent knowledge of the specific WS-Security specifications. Perhaps WS-Security headers can also be created and packed into the XML request by using SoapClient::__setSoapHeaders() and the appropriate SoapHeader s olurdu ama ben özel {[(bırakarak, bu çalışacaktır şüphe yalnız olasılık olarak 0)]} uzantısı.

Basit bir SoapClient uzantısı olacaktır

class My_SoapClient extends SoapClient
{
    protected function __doRequest($request, $location, $action, $version) 
    {
        /*
         * $request is a XML string representation of the SOAP request
         * that can e.g. be loaded into a DomDocument to make it modifiable.
         */
        $domRequest = new DOMDocument();
        $domRequest->loadXML($request);

        // modify XML using the DOM API, e.g. get the <s:Header>-tag 
        // and add your custom headers
        $xp = new DOMXPath($domRequest);
        $xp->registerNamespace('s', 'http://www.w3.org/2003/05/soap-envelope');
        // fails if no <s:Header> is found - error checking needed
        $header = $xp->query('/s:Envelope/s:Header')->item(0);

        // now add your custom header
        $usernameToken = $domRequest->createElementNS('http://schemas.xmlsoap.org/ws/2002/07/secext', 'wsse:UsernameToken');
        $username = $domRequest->createElementNS('http://schemas.xmlsoap.org/ws/2002/07/secext', 'wsse:Username', 'userid');
        $password = $domRequest->createElementNS('http://schemas.xmlsoap.org/ws/2002/07/secext', 'wsse:Password', 'password');
        $usernameToken->appendChild($username);
        $usernameToken->appendChild($password);
        $header->appendChild($usernameToken);

        $request = $domRequest->saveXML();
        return parent::__doRequest($request, $location, $action, $version);
    }
}

Temel bir WS-Security kimlik doğrulaması için SOAP-başlığına aşağıdaki eklemek gerekir:

<wsse:UsernameToken>
    <wsse:Username>userid</wsse:Username>
    <wsse:Password>password</wsse:Password>                                 
</wsse:UsernameToken>

Ama yukarıda söylediğim gibi: Ben WS-Security şartname ve verilen servis mimarisi hakkında daha fazla bilgi bu çalışma almak için gerekli olduğunu düşünüyorum.

If you need an enterprise grade solution for the whole WS-* specification range and if you can install PHP modules you should have a look at the WSO2 Web Services Framework for PHP (WSO2 WSF/PHP)

Sadece bir WSSE compilant kimlik oluşturmak için SoapHeader uzatmak:

class WsseAuthHeader extends SoapHeader {

private $wss_ns = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd';

function __construct($user, $pass, $ns = null) {
    if ($ns) {
        $this->wss_ns = $ns;
    }

    $auth = new stdClass();
    $auth->Username = new SoapVar($user, XSD_STRING, NULL, $this->wss_ns, NULL, $this->wss_ns); 
    $auth->Password = new SoapVar($pass, XSD_STRING, NULL, $this->wss_ns, NULL, $this->wss_ns);

    $username_token = new stdClass();
    $username_token->UsernameToken = new SoapVar($auth, SOAP_ENC_OBJECT, NULL, $this->wss_ns, 'UsernameToken', $this->wss_ns); 

    $security_sv = new SoapVar(
        new SoapVar($username_token, SOAP_ENC_OBJECT, NULL, $this->wss_ns, 'UsernameToken', $this->wss_ns),
        SOAP_ENC_OBJECT, NULL, $this->wss_ns, 'Security', $this->wss_ns);
    parent::__construct($this->wss_ns, 'Security', $security_sv, true);
}
}



$wsse_header = new WsseAuthHeader($username, $password);
$x = new SoapClient('{...}', array("trace" => 1, "exception" => 0));
$x->__setSoapHeaders(array($wsse_header));

Ben mevcut SoapClient kitaplığı uzanan daha basit bir çözümü var.

Adım 1: WSSE başlıkları için bir yapı oluşturmak için iki sınıfları oluşturma

class clsWSSEAuth {
    private $Username;
    private $Password;
    function __construct($username, $password) {
        $this->Username=$username;
        $this->Password=$password;
    }
}

class clsWSSEToken {
    private $UsernameToken;
    function __construct ($innerVal){
        $this->UsernameToken = $innerVal;
    }
}

Adım 2: UserName ve Password için Sabun değişkenleri oluşturma

$username = 1111;
$password = 1111;

//Check with your provider which security name-space they are using.
$strWSSENS = "http://schemas.xmlsoap.org/ws/2002/07/secext";

$objSoapVarUser = new SoapVar($username, XSD_STRING, NULL, $strWSSENS, NULL, $strWSSENS);
$objSoapVarPass = new SoapVar($password, XSD_STRING, NULL, $strWSSENS, NULL, $strWSSENS);

Adım 3: Auth Sınıf Nesne oluşturma ve sabun var geçmek

$objWSSEAuth = new clsWSSEAuth($objSoapVarUser, $objSoapVarPass);

Adım 4: Auth sınıf nesnesi üzerinden SoapVar oluşturun

$objSoapVarWSSEAuth = new SoapVar($objWSSEAuth, SOAP_ENC_OBJECT, NULL, $strWSSENS, 'UsernameToken', $strWSSENS);

Adım 5: Token Sınıf nesne oluşturma

$objWSSEToken = new clsWSSEToken($objSoapVarWSSEAuth);

Step6: Token sınıf nesnesi üzerinden SoapVar oluşturun

$objSoapVarWSSEToken = new SoapVar($objWSSEToken, SOAP_ENC_OBJECT, NULL, $strWSSENS, 'UsernameToken', $strWSSENS);

7. adım: 'Güvenlik' düğüm için SoapVar oluştur

$objSoapVarHeaderVal=new SoapVar($objSoapVarWSSEToken, SOAP_ENC_OBJECT, NULL, $strWSSENS, 'Security', $strWSSENS);

8. adım: Güvenlik soapvar üzerinden başlığı nesne oluşturma

$objSoapVarWSSEHeader = new SoapHeader($strWSSENS, 'Security', $objSoapVarHeaderVal,true, 'http://abce.com');

//Third parameter here makes 'mustUnderstand=1
//Forth parameter generates 'actor="http://abce.com"'

Adım9: Sabun Client nesne oluşturma

$objClient = new SoapClient($WSDL, $arrOptions);

10. adım: SoapClient nesne ayarlama başlıkları

$objClient->__setSoapHeaders(array($objSoapVarWSSEHeader));

Adım 11: yöntemine son çağrı

$objResponse = $objClient->__soapCall($strMethod, $requestPayloadString);

Bir şifre güvenliğini sindirmek için, aşağıdakileri kullanabilirsiniz:

   /**
    * This function implements a WS-Security digest authentification for PHP.
    *
    * @access private
    * @param string $user
    * @param string $password
    * @return string
    */
   function generateWSSecurity($user, $password)
   {
      // Creating date using yyyy-mm-ddThh:mm:ssZ format
      $tm_created = gmdate('Y-m-d\TH:i:s\Z');
      $tm_expires = gmdate('Y-m-d\TH:i:s\Z', gmdate('U') + 180);

      // Generating, packing and encoding a random number
      $simple_nonce = mt_rand();
      $encoded_nonce = base64_encode(pack('H*', $simple_nonce));

      // Compiling WSS string
      $passdigest = base64_encode(pack('H*',
            sha1(pack('H*', $simple_nonce) . pack('a*', $tm_created) . pack('a*', $password))));

      // Initializing namespaces
      $ns_wsse = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd';
      $ns_wsu = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd';
      $password_type = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest';
      $encoding_type = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary';

      // Creating WSS identification header using SimpleXML
      $root = new \SimpleXMLElement('<root/>');

      $security = $root->addChild('wsse:Security', null, $ns_wsse);

      $timestamp = $security->addChild('wsu:Timestamp', null, $ns_wsu);
      $timestamp->addAttribute('wsu:Id', 'Timestamp-28');
      $timestamp->addChild('wsu:Created', $tm_created, $ns_wsu);
      $timestamp->addChild('wsu:Expires', $tm_expires, $ns_wsu);

      $usernameToken = $security->addChild('wsse:UsernameToken', null, $ns_wsse);
      $usernameToken->addChild('wsse:Username', $user, $ns_wsse);

      $password = $usernameToken->addChild('wsse:Password', $passdigest, $ns_wsse);
      $password->addAttribute('Type', $password_type);

      $nonce = $usernameToken->addChild('wsse:Nonce', $encoded_nonce, $ns_wsse);
      $nonce->addAttribute('EncodingType', $encoding_type);

      $usernameToken->addChild('wsu:Created', $tm_created, $ns_wsu);

      // Recovering XML value from that object
      $root->registerXPathNamespace('wsse', $ns_wsse);
      $full = $root->xpath('/root/wsse:Security');
      $auth = $full[0]->asXML();

      return $auth;
   }

PHP SoapClient ile kullanmak, bu şekilde kullanın:

function soapClientWSSecurityHeader($user, $password)
{
   return new \SoapHeader('http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd',
      'Security', new \SoapVar(generateWSSecurity($user, $password), XSD_ANYXML), true
   );
}

$client = new \SoapClient('http://endpoint');
$client->__setSoapHeaders(soapClientWSSecurityHeader('myUser', 'myPassword'));
// $client->myService(array('param' => 'value', ...);
$client = new SoapClient("some.wsdl", array('login'    => "some_name",
                                            'password' => "some_password"));

From the php documentation