2012-02-07 15 views
5

Scrivo qui perché sto lavorando per trasformare un client Webservice PHP in C# (VS2010).Web service - Client C# e server Apache Autenticazione di base - Errore HTTP 400 Richiesta errata

Il progetto è in Framework4 ma il servizio Web è stato aggiunto in VS2010 come un servizio Web compatibile con Framework2 (Riferimento Web con WSDL).

Attualmente sto lavorando solo su un webservice classico (un test di Helloworld).

Con il client C# non ho alcun problema, invio un testo al servizio web e il servizio web risponde ripensando il testo. Non ho errori nel server Apache.

Se posso attivare l'autenticazione di base nel server .htaccess apache (ospitare il server webservice), quindi nel client C# ho questo errore:

Eccezione: WebException Bad Request con HTTP stato 400: Bad Request .

In Apache log degli errori vedo questa linea:

[Thu Feb 02 23:52:06 2012] [error] [client XX.XX.XX.XX] Invalid URI in request 
<?xml version="1.0" encoding="utf-8"?> 
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"  
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:tns="https://www.domaine.com/api/helloworld/webservices.php?wsdl" 
xmlns:types="https://www.domaine.com/api/helloworld/webservices.php?wsdl/encodedTypes" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org 
/2001/XMLSchema"> 
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> 
<tns:bonjour><prenom xsi:type="xsd:string">Toto</prenom></tns:bonjour> 
</soap:Body> 
</soap:Envelope> 
POST /api/helloworld/webservices.php HTTP/1.1 

.

Sono sicuro che le credenziali non funzionano perché quando provo con un falso utente e una password ho sempre la 400 Bad Request.

Il codice del client C# è: // Creiamo il servizio web WebService mywebservice = new WebService();

// We define BASIC Authentication    
CredentialCache myCredentials = new CredentialCache();   
NetworkCredential netCred = new NetworkCredential("User1", "Pass1");  
myCredentials.Add(new Uri(mywebservice.Url), "Basic", netCred); 
myCredentials.PreAuthenticate = true; 
mywebservice.Credentials = myCredentials; 

// We define the UserAgent 
mywebservice.UserAgent = ".NET Framework"; 

// We call the function of webservice 
string retour = mywebservice.bonjour("Tata"); 

// We show the return 
MessageBox.Show(retour, "Retour de l'API", MessageBoxButtons.OK, MessageBoxIcon.Information); 

.

Il .htaccess: # Non mostrare elenchi di directory per gli URL che si associano a una directory. Opzioni -Index

# Se logue avec un compte AD 
AuthType Basic 
AuthBasicProvider ldap 
AuthName "Acces au webservice" 
AuthLDAPURL ldap://127.0.0.1:389/ou=clients,dc=domaine,dc=com?mail 
Require valid-user 

.

Se elimino il tutto .htaccess file, funziona ... ma senza autenticazione :(

vi posto anche la richiesta e la risposta con .htaccess (che non funziona):.

POST https://www.domaine.com/api/login_ovh_pnp/webservices.php HTTP/1.1 
User-Agent: .NET Framework 
VsDebuggerCausalityData: uIDPo9/Tb/xbJxtKvSNra7boyJsAAAAAQcQin1OhXXXXXXXXXXX/KqROJW0w1FhAcrrhI1sGQACQAA 
Content-Type: text/xml; charset=utf-8 
SOAPAction: "https://www.domaine.com/api/login_ovh_pnp/webservices.php?wsdl#bonjour" 
Authorization: Basic bHZlaXJtYW5AYXF1aWxhLWXXXXXXXXXXXbmcuZnI6ZHluYXRlcmE3OA== 
Host: www.domaine.com 
Content-Length: 623 
Expect: 100-continue 

<?xml version="1.0" encoding="utf-8"?> 
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:tns="https://www.domaine.com/api/login_ovh_pnp/webservices.php?wsdl" 
xmlns:types="https://www.domaine.com/api/login_ovh_pnp/webservices.php?wsdl 
/encodedTypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> 
<tns:bonjour> 
<prenom xsi:type="xsd:string">Tata</prenom> 
</tns:bonjour> 
</soap:Body>  
</soap:Envelope> 

===================================== 
===================================== 

HTTP/1.1 400 Bad Request 
Date: Mon, 06 Feb 2012 13:40:32 GMT 
Server: Apache 
Vary: Accept-Encoding 
Content-Length: 226 
Connection: close 
Content-Type: text/html; charset=iso-8859-1 

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> 
<html><head> 
<title>400 Bad Request</title> 
</head><body> 
<h1>Bad Request</h1> 
<p>Your browser sent a request that this server could not understand.<br /> 
</p> 
</body></html> 

E per finire la richiesta senza .htaccess:

POST https://www.domaine.com/api/login_ovh_pnp/webservices.php HTTP/1.1 
User-Agent: .NET Framework 
VsDebuggerCausalityData:  
uIDPo4r/MO3TgmdMkQiWHfkXoWwAAAAA1krYOM0NBkS9vLzFQe3Vmln8F3GXClFNrTWXL/L622YACQAA 
Content-Type: text/xml; charset=utf-8 
SOAPAction: "https://www.domaine.com/api/login_ovh_pnp/webservices.php?wsdl#bonjour" 
Host: www.domaine.com 
Content-Length: 623 
Expect: 100-continue 
Connection: Keep-Alive 

<?xml version="1.0" encoding="utf-8"?> 
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:tns="https://www.domaine.com/api/login_ovh_pnp/webservices.php?wsdl" 
xmlns:types="https://www.domaine.com/api/login_ovh_pnp/webservices.php?wsdl 
/encodedTypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> 
<tns:bonjour> 
<prenom xsi:type="xsd:string">Tata</prenom> 
</tns:bonjour> 
</soap:Body></soap:Envelope> 

===================================== 
===================================== 

HTTP/1.1 200 OK 
Date: Mon, 06 Feb 2012 13:51:31 GMT 
Server: Apache 
X-SOAP-Server: NuSOAP/0.9.5 (1.123) 
Content-Length: 575 
Vary: Accept-Encoding 
Keep-Alive: timeout=15, max=100 
Connection: Keep-Alive 
Content-Type: text/xml; charset=ISO-8859-1 

<?xml version="1.0" encoding="ISO-8859-1"?> 
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"> 
<SOAP-ENV:Body> 
<ns1:bonjourResponse xmlns:ns1="https://supervision.dynatera.net/api/login_ovh_pnp/webservices.php?wsdl"> 
<return xsi:type="xsd:string">Bonjour Tata</return></ns1:bonjourResponse> 
</SOAP-ENV:Body> 
</SOAP-ENV:Envelope> 

.

Grazie mille per il vostro aiuto su questo complesso problema perché ho cercato molte volte senza trovare nulla per risolvere questo problema.

+0

Puoi chiamare il servizio sicuro con soapui? – davidfrancis

+0

Post modificato per rimuovere utente/password –

risposta

0

credenziali impostate nel codice non corrisponde credenziali inviate nella richiesta

Authorization: Basic bHZlaXJtYW5AYXF1aWxxxxxx1bHRpbmcuZnI6ZHluYXRlcmE3OA== 

Il codice impostato prossimo credenziali per l'autenticazione di base:

// We define BASIC Authentication    
CredentialCache myCredentials = new CredentialCache();   
NetworkCredential netCred = new NetworkCredential("User1", "Pass1"); 

Ma credenziali all'interno Autorizzazione token di richiesta sono:

"[email protected]:dynXXXXXXX" 

(ti consiglio di modificare il tuo post e rimuovere la base64 token di autenticazione, inoltre è una buona idea per cambiare la password di rete ASAP < < fatto)

4

Ho anche avuto questo problema ... Quando si definisce NetworkCredentials non venga inviato nell'intestazione HTTP, e quindi non header 'autorizzazione' ...

quello che ho fatto e ha funzionato per me è stato:

ho creato una classe che implementa IClientMessageInspector e implementare il metodo BeforeSendRequest:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

using System.ServiceModel.Dispatcher; 
using System.ServiceModel.Channels; 

namespace BasicAuth 
{ 
    public sealed class MessageHttpHeaderInspector : IClientMessageInspector 
    { 
     private string userName; 
     private string password; 

     #region Constructor 

     public MessageHttpHeaderInspector(string userName, string password) 
     { 
      this.userName = userName; 
      this.password = password; 
     } 

     #endregion 

     #region IClientMessageInspector Members 

     public void AfterReceiveReply(ref Message reply, object correlationState) 
     { 
      //throw new NotImplementedException(); 
     } 

     public object BeforeSendRequest(ref Message request, System.ServiceModel.IClientChannel channel) 
     { 
      HttpRequestMessageProperty httpRequest; 

      if (request.Properties.ContainsKey(HttpRequestMessageProperty.Name)) 
      { 
       httpRequest = request.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty; 
      } 
      else 
      { 
       httpRequest = new HttpRequestMessageProperty(); 
       request.Properties.Add(HttpRequestMessageProperty.Name, httpRequest); 
      } 

      if (httpRequest != null) 
      { 
       string credentials = this.CreateBasicAuthenticationCredentials(this.userName, this.password); 
       httpRequest.Headers.Add(System.Net.HttpRequestHeader.Authorization, credentials); 
      } 

      return request; 
     } 

     #endregion 

     #region Private Worker Methods 

     private string CreateBasicAuthenticationCredentials(string userName, string password) 
     { 
      string returnValue = string.Empty; 
      string base64UsernamePassword = Convert.ToBase64String(Encoding.ASCII.GetBytes(String.Format("{0}:{1}", userName, password))); 

      returnValue = String.Format("Basic {0}", base64UsernamePassword); 

      return returnValue; 
     } 

     #endregion 
    } 
} 

Poi ho creato una classe che implementa IEndpointBehavior e implementa il metodo ApplyClientBehavior:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

using System.ServiceModel; 
using System.ServiceModel.Description; 
using System.ServiceModel.Dispatcher; 

namespace BasicAuth 
{ 
    public sealed class CustomEndpointCallBehavior : IEndpointBehavior 
    { 
     private string userName;  
     private string password; 

     #region Constructor 

     public CustomEndpointCallBehavior(string userName, string password) 
     { 
      this.userName = userName;  
      this.password = password; 
     } 

     #endregion 

     #region IEndpointBehavior Members 

     public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) 
     { 
      //throw new NotImplementedException(); 
     } 

     public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) 
     { 
      clientRuntime.MessageInspectors.Add(new MessageHttpHeaderInspector(this.userName, this.password)); 
     } 

     public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) 
     { 
      //throw new NotImplementedException(); 
     } 

     public void Validate(ServiceEndpoint endpoint) 
     { 
      //throw new NotImplementedException(); 
     } 

     #endregion 
    } 
} 

Allora avete bisogno di applicare questo comportamento al proxy:

mywebservice.Endpoint.Behaviors.Add(new CustomEndpointCallBehavior("User1", "Pass1")); 

Date un'occhiata al seguente:

Questo dovrebbe fare il trucco ... auguro che funziona per voi!

+1

Grazie mille. Questo ha funzionato senza problemi. –

Problemi correlati