如何从Symfony 2.0读取Soap WSSE Headers



我正在尝试在 Web 服务 API 上实现 WSSE 身份验证。我在symfony官方网站上遵循了本教程。我使用 SoapUI 发送请求,带有安全标头:

POST http://dev.sellerphp.com/app_dev.php/wsapi/soap/ordersfollowup HTTP/1.0
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: "http://dev.sellerphp.com/app_dev.php/wsapi/soap/ordersfollowup"
Content-Length: 1520
Host: dev.sellerphp.com
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
<soapenv:Envelope xmlns:ord="https://dev.sellerphp.com/app_dev.php/wsapi/soap/ordersfollowup?wsdl" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsap="http://wsapi.sellerphp.com/">
   <soapenv:Header>
       <wsse:Security soap:mustUnderstand="1" 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">
           <wsu:Timestamp wsu:Id="TS-14">
               <wsu:Created>2012-10-10T09:36:10Z</wsu:Created>
               <wsu:Expires>2012-10-10T09:52:50Z</wsu:Expires>
           </wsu:Timestamp>
           <wsse:UsernameToken wsu:Id="UsernameToken-13">
               <wsse:Username>myUsername</wsse:Username>
               <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">hb5AJ7CT2tMSQymSsxwvc8J/xoI=</wsse:Password> 
               <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">PEo//Z/yGF5/HCW6rkCuwQ==</wsse:Nonce>
               <wsu:Created>2012-10-10T09:36:10.485Z</wsu:Created>
           </wsse:UsernameToken>
        </wsse:Security>
   </soapenv:Header>
   <soapenv:Body>
      <wsap:setTracking>
         <input>
            <!--1 to 10 repetitions:-->
            <OrderItemTracking>
               <order-item-id>?</order-item-id>
               <tracking-number>?</tracking-number>
            </OrderItemTracking>
         </input>
      </wsap:setTracking>
   </soapenv:Body>
</soapenv:Envelope>

在服务器端,WsseListener 类不读取 SOAP 标头...该示例仅涉及标头在请求级别定义,但它们仅嵌入在 SOAP 信封中:

 public function handle(GetResponseEvent $event)
   {
      $request = $event->getRequest();
      $wsseRegex = '/UsernameToken Username="([^"]+)", PasswordDigest="([^"]+)", Nonce="([^"]+)", Created="([^"]+)"/';
      if (!$request->headers->has('x-wsse') || 1 !== preg_match($wsseRegex, $request->headers->get('x-wsse'), $matches))
      {
         return;
      }
      // ########### It never reached this line, never found any headers...
      var_dump($matches);exit;
      $token = new WsseUserToken();
      $token->setUser($matches[1]);
      $token->digest = $matches[2];
      $token->nonce = $matches[3];
      $token->created = $matches[4];
      try
      {
         $authToken = $this->authenticationManager->authenticate($token);
         $this->securityContext->setToken($authToken);
      }
      catch (AuthenticationException $failed)
      {
         // ... you might log something here
         // To deny the authentication clear the token. This will redirect to the login page.
         // $this->securityContext->setToken(null);
         // return;
         // Deny authentication with a '403 Forbidden' HTTP response
         $response = new Response();
         $response->setStatusCode(403);
         $event->setResponse($response);
      }
   }

我不知道如何从侦听器读取肥皂:标头标头。你可以帮我吗?

我终于承认,Symfony提供的示例意味着WSSE标头是由HTTP层而不是SOAP信封带来的。所以我做了一个解决方法来读取 SOAP 标头:

WsseListener 句柄方法:

   public function handle(GetResponseEvent $event)
   {
      $request = $event->getRequest();
      $decodedHeaders = WsseHeadersDecoder::getHeaders($request);
      if (!$decodedHeaders || !is_array($decodedHeaders))
      {
         return;
      }
      $token = new WsseUserToken();
      $token->setUser($decodedHeaders['username']);
      $token->digest = $decodedHeaders['passwordDigest'];
      $token->nonce = $decodedHeaders['nonce'];
      $token->created = $decodedHeaders['created'];
      // ...
   }

WsseHeadersDecoder::getHeaders Method :

   static public function getHeaders(Request $request)
   {
      //HTTP headers (as described here : http://symfony.com/doc/2.0/cookbook/security/custom_authentication_provider.html#the-listener
      if ($request->headers->has('x-wsse'))
      {
         $wsseRegex = '/UsernameToken Username="([^"]+)", PasswordDigest="([^"]+)", Nonce="([^"]+)", Created="([^"]+)"/';
         if (1 !== preg_match($wsseRegex, $request->headers->get('x-wsse'), $matches))
         {
            return false;
         }
         else
         {
            $username = $matches[1];
            $passwordDigest = $matches[2];
            $nonce = $matches[3];
            $created = $matches[4];
         }
      }
      //Classic SOAP headers
      else
      {
         //PéCé: Clear XML namespace prefixes to handle with SimpleXML
         $decodedRequest = preg_replace("/(</?)([-w]+):([^>]*>)/", "$1$3", $request->getContent());
         $xmlRequest = simplexml_load_string($decodedRequest);
         if (
            !isset($xmlRequest->Header->Security->UsernameToken->Username)
            || !isset($xmlRequest->Header->Security->UsernameToken->Password)
            || !isset($xmlRequest->Header->Security->UsernameToken->Nonce)
            || !isset($xmlRequest->Header->Security->UsernameToken->Created)
         )
         {
            return false;
         }
         else
         {
            $username = (string) $xmlRequest->Header->Security->UsernameToken->Username;
            $passwordDigest = (string) $xmlRequest->Header->Security->UsernameToken->Password;
            $nonce = (string) $xmlRequest->Header->Security->UsernameToken->Nonce;
            $created = (string) $xmlRequest->Header->Security->UsernameToken->Created;
         }
      }
      return array (
              'username' => $username, 'passwordDigest' => $passwordDigest, 'nonce' => $nonce, 'created' => $created
      );
   }

最新更新