2012-02-07 25 views
5

Escribo aquí porque estoy trabajando para transformar un cliente de servicio web de PHP a C# (VS2010).Servicio web - Autenticación básica de C# Client y Apache Server - Error HTTP 400 Bad Request

Los proyectos están en Framework4 pero el servicio web se agregó en VS2010 como un servicio web compatible con Framework2 (referencia web con WSDL).

Actualmente estoy trabajando solo en un servicio web clásico (una prueba Helloworld).

Con el cliente C# no tengo problema, le envío un mensaje de texto al servicio web y el servicio web responde devolviendo el texto. No tengo ningún error en el servidor Apache.

Si activo la autenticación básica en el servidor Apache .htaccess (alojar el servidor de servicio web), por lo que en el cliente de C# Tengo este error:

Excepción: WebException Solicitud incorrecta con estado HTTP 400: Solicitud incorrecta .

En el registro de errores de Apache que ver esta línea:

[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 

.

Estoy seguro de que son las credenciales que no funcionan porque cuando intento con un usuario y contraseña falsos siempre tengo la 400 Bad Request.

El código de C# Client es: // Creamos el servicio 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); 

.

The .htaccess: # No mostrar las listas de directorios para las URL que se asignan a un directorio. Opciones -Indexes

# 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 

.

Si elimino el archivo .htaccess todo lo que está funcionando ... pero sin autenticación :(

he puesto también la solicitud y la respuesta con .htaccess (no funciona):.

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> 

Y para acabado de la solicitud sin .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> 

.

Muchas gracias por su ayuda en este complejo problema porque he buscado muchas veces sin encontrar nada para solucionar este problema.

+0

¿Puede llamar al servicio de seguridad con soapui? – davidfrancis

+0

Publicación editada para eliminar usuario/contraseña –

Respuesta

0

Credenciales establecidos en el código no coincide con credenciales enviadas en la solicitud de

Authorization: Basic bHZlaXJtYW5AYXF1aWxxxxxx1bHRpbmcuZnI6ZHluYXRlcmE3OA== 

Su código situado junto credenciales para la autenticación básica:

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

Pero credenciales dentro de Autorización de petición de señal son:

"[email protected]:dynXXXXXXX" 

(le recomiendo que edite su publicación y quite la base64 tokens de autenticación, además, es una buena idea para cambiar la contraseña de red lo antes posible < < hecho)

4

También he tenido este problema ... Al definir NetworkCredentials no consigue enviado en la cabecera HTTP, y por lo tanto no se cabecera 'Autorización' ...

lo que hice y funcionó para mí fue:

he creado una clase que implementa IClientMessageInspector y poner en práctica el método 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 
    } 
} 

Entonces creó una clase que implementa IEndpointBehavior e implementa el método 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 
    } 
} 

Luego hay que aplicar este comportamiento al proxy:

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

Tener un vistazo a la siguiente:

Esto debería hacer el truco ... espero que funcione para usted!

+1

Gracias a un millón. Esto funcionó sin ningún problema. –

Cuestiones relacionadas