2009-09-22 4 views
2

Avoir un problème tout en faisant appel à l'aide POX REST WCF avec WebHttpBinding réglé sur l'authentification de base (HttpClientCredentialType.Basic)demande tout en faisant appel POX REST en utilisant WCF avec WebHttpBinding réglé sur l'authentification de base

Au lieu d'un appel du client avec "Authorization: Basic" spécifié dans HTTP Header, deux appels sont effectués. Premier appel sans authentification à toutes les réponses de service avec 401 Erreur non autorisée, deuxième appel avec des informations d'authentification appropriées.

Cela semble être géré par le service WCF sans aucun hoquet du tout. Appeler des services tiers crée évidemment un problème car ils répondent immédiatement avec une erreur.

Code de service:

[ServiceContract] 
public interface IService 
{ 
    [OperationContract] 
    [WebInvoke(BodyStyle = WebMessageBodyStyle.Bare, 
     RequestFormat = WebMessageFormat.Xml, 
     UriTemplate = "")] 
    Message SendData(Message message); 

} 

public class Service : IService 
{ 
    public Message SendData(Message message) 
    {   return Message.CreateMessage(MessageVersion.None, String.Empty, "test"); 
    } 
} 

Code client:

public class Client: WebChannelFactory<IService>, IService 
{ 
    public Client(Uri baseUri, string userName, string password) 
     : base(CreateBinding(), 
       baseUri) 
    { 
     Credentials.UserName.UserName = userName; 
     Credentials.UserName.Password = password; 
    } 

    public Message SendData(Message requestMessage) 
    { 
     var channel = CreateChannel(); 
     Message responseMessage = channel.SendData(requestMessage); 
     return responseMessage; 
    } 

    private static Binding CreateBinding() 
    { 
     var binding = new WebHttpBinding(); 
     binding.Security.Mode = WebHttpSecurityMode.TransportCredentialOnly; 
     binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic; 
     return binding; 
    } 

} 

En utilisant tcptrace Je vois ces demandes dos à dos:

POST/HTTP/1.1 
Content-Type: application/xml; charset=utf-8 
VsDebuggerCausalityData: uIDPo2lH6p+lUOdFmrqDKGWYeQkAAAAA7+Y4QR6wNUWZmwCaasMx7xrfcJZxph9NocstwCh8NQsACQAA 
Host: localhost:9090 
Content-Length: 89 
Expect: 100-continue 
Connection: Keep-Alive 

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">test request</string> 

POST/HTTP/1.1 
Content-Type: application/xml; charset=utf-8 
VsDebuggerCausalityData: uIDPo2lH6p+lUOdFmrqDKGWYeQkAAAAA7+Y4QR6wNUWZmwCaasMx7xrfcJZxph9NocstwCh8NQsACQAA 
Authorization: Basic dGVzdDp0ZXN0 
Host: localhost:9090 
Content-Length: 89 
Expect: 100-continue 

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">test request</string> 

Remarque seulement deuxième appel contient: Autorisation: Basic dGVzdDp0ZXN0 Comment arrêter la première requête (sans autorisation) à faire?

solution échantillon avec l'utilitaire tcptrace peut être téléchargé ici:

WCF-BasicAuthenticationIssue.zip

Répondre

3

Le problème est en fait avec ces tiers. Per RFC 2617 L'authentification de base se fait en deux appels, tout comme Digest. Le serveur doit répondre au premier appel à un défi contenant un royaume:

Dès réception d'une demande non autorisée pour un URI dans l'espace de protection
, le serveur d'origine PEUT répondre à un défi comme
ce qui suit:

WWW-Authenticate: Basic realm="WallyWorld" 

où « WallyWorld » est la chaîne attribuée par le serveur pour identifier
l'espace de protection de la Request-URI

Le critère d'évaluation WCF préauthentification seulement ultérieurs appels après la première. Le tout premier appel effectué par un domaine d'application vers une ressource ne contiendra pas le nom d'utilisateur et le mot de passe d'en-tête de base.

Voir aussi What happened to the PreAuthenticate flag in WCF.

+0

Ramus, Merci beaucoup pour vous répondre. Cela clarifie beaucoup. –

+0

Vous dites que l'authentification de base se fait en deux appels, mais ne devriez-vous pas dire que l'authentification de base peut être effectuée en deux appels? RFC 2617 ne dit pas explicitement que la première demande ne peut pas contenir les informations d'identification. –

4

donc basée sur la réponse de Remus ceci est ma solution

 public Message SendData(Message requestMessage) 
    { 
     var channel = CreateChannel(); 
     Message responseMessage; 
     using (new OperationContextScope((IClientChannel)channel)) 
     { 
      WebOperationContext.Current.OutgoingRequest 
       .Headers[HttpRequestHeader.Authorization] = "Basic " 
       + Convert.ToBase64String(Encoding.ASCII.GetBytes(
       Credentials.UserName.UserName + ":" + Credentials.UserName.Password)); 
      responseMessage = channel.SendData(requestMessage); 
     } 
     return responseMessage; 
    } 

Je suis simplement forcer la première demande de sortir avec l'autorisation de base

+0

Yeap, c'est ce que tout le monde fait, ajouter les en-têtes manuellement. –

+0

Merci Jakub, votre code a parfaitement fonctionné en appelant un service WCF REST avec une authentification de base personnalisée implémentée avec WcfRestContrib. –

Questions connexes