Errore nel client WCF che utilizza il servizio Web di Axis 2 con WS-Security UsernameToken PasswordDigest schema di autenticazione

Ho un client WCF che si connette a un servizio Web Axis2 basato su Java (fuori dal mio controllo). Sta per essere applicato a WS-Security e ho bisogno di riparare il client .NET. Tuttavia, sto lottando per fornire l’autenticazione corretta. Sono consapevole che WSE 3.0 potrebbe renderlo più semplice, ma preferirei non tornare a una tecnologia obsoleta.

Problemi simili (non risolti), includi questo , questo e questo .

Il messaggio SOAP dovrebbe assomigliare a questo:

    2010-05-28T12:50:33.675+01:00  

Tuttavia, il mio è simile a questo:

     2010-06-23T10:31:23.441Z 2010-06-23T10:36:23.441Z            

Il mio client assomiglia a questo: PS Nota il parametro SecurityHeaderType richiesto . Cos’è quello?

     public MyAck SendRequest(MyRequest request) { RemoteServicePortTypeClient client = new RemoteServicePortTypeClient(); client.ClientCredentials.UserName.UserName = "JAY"; client.ClientCredentials.UserName.Password = "AND"; // what is the difference between the two different Credential types?? //client.ClientCredentials.HttpDigest.ClientCredential.UserName = "SILENT"; //client.ClientCredentials.HttpDigest.ClientCredential.Password = "BOB"; SecurityHeaderType sht = new SecurityHeaderType(); //sht.Any = ???; // How do I use this??? //sht.AnyAttr = ???; // How do I use this ??? // SecurityHeaderType is a required parameter return client.RemoteServiceOperation_Provider(sht, request); } 

    L’attuale associazione è la seguente:

             

    Ho anche provato un’associazione personalizzata e ho ottenuto un errore simile:

            

    E endpoint (Indirizzo ovviamente cambiato …):

      

    L’errore personalizzato che viene restituito è il seguente:

     0 UNEXPECTED  2010-06-23T13:28:54Z 

    Ho letto molto su intestazioni personalizzate, token, associazioni e il mio cervello è completamente confuso. Qualcuno può suggerire una procedura passo passo per l’invio del messaggio nel formato giusto?

    Questa sembra essere la via da seguire per WCF, utilizzando token personalizzati, ma come si dovrebbe applicare il digest e il nonce come richiesto?

    Qualsiasi aiuto accolto.

    AGGIORNARE

    Ho avuto un successo limitato. Ho usato la libreria Microsoft.Web.Services3 per creare un nome utenteToken con il digest corretto. Ho quindi creato il mio comportamento personalizzato e nel metodo BeforeSendRequest ho fatto quanto segue per iniettare l’intestazione:

     object IClientMessageInspector.BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel) { UsernameToken ut = new UsernameToken("USERNAME", "PASSWORD", PasswordOption.SendHashed); XmlElement securityElement = ut.GetXml(new XmlDocument()); MessageHeader myHeader = MessageHeader.CreateHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", securityElement, false); request.Headers.Add(myHeader); return Convert.DBNull; } 

    Aggiungo il comportamento in questo modo:

     CustomBehavior behavior = new CustomBehavior("USERNAME", "PASSWORD"); client.Endpoint.Behaviors.Add(behavior); 

    Ora posso vedere le intestazioni che attraversano:

                 2010-06-24T16:23:58Z    

    Ma sto ricevendo l’errore:

      soapenv:Server WSDoAllReceiver: security processing failed; nested exception is: org.apache.ws.security.WSSecurityException: General security error (WSSecurityEngine: Callback supplied no password for: USERNAME) urn:Remote_Provider   0 UNEXPECTED  2010-06-24T17:23:59Z    

    Sembra che ci sia un attributo Type mancante sul nodo della password:

     Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest" 

    Tuttavia, non sono sicuro che le impostazioni di tracciamento e registrazione della sicurezza siano coperte eliminando gli attributi e il contenuto di tali nodes. Ho tentato di utilizzare l’impostazione logKnownPii nella registrazione diagnostica, ma le informazioni sulla sicurezza rimangono oscurate. Qualche idea su quello?

    Posso confermare che l’AGGIORNAMENTO dalla mia domanda funziona effettivamente:

     object IClientMessageInspector.BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel) { UsernameToken ut = new UsernameToken("USERNAME", "PASSWORD", PasswordOption.SendHashed); XmlElement securityElement = ut.GetXml(new XmlDocument()); MessageHeader myHeader = MessageHeader.CreateHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", securityElement, false); request.Headers.Add(myHeader); return Convert.DBNull; } 

    E il cliente:

     CustomBehavior behavior = new CustomBehavior("USERNAME", "PASSWORD"); client.Endpoint.Behaviors.Add(behavior); 

    Il messaggio di errore non era correlato. L’intestazione di sicurezza funziona con una baseHttpBinding molto semplice:

          

    Esempio di codice di questo in azione può essere trovato sul mio blog: http://benpowell.org/supporting-the-ws-i-basic-profile-password-digest-in-a-wcf-client-proxy/

    Questa domanda è ben scritta – molte grazie. In riferimento al commento “Come usare questo” di @ Junto, risulta che il parametro SecurityHeader sul metodo di servizio può essere utilizzato per aggiungere l’intestazione. Ho incluso un esempio qui sotto. Credo che quello che sta succedendo sia che lo strumento SvcUtil.exe stia bargando durante il tentativo di leggere i DTD WS *. Questo non è ovvio quando si utilizza la procedura guidata “Aggiungi riferimento servizio”. Ma è molto ovvio quando si esegue svcutil.exe dalla riga di comando. Poiché svcutil.exe non riesce a leggere i DTD WS *, l’object SecurityHeader non è ben sviluppato. Ma Microsoft ti offre un out con la proprietà .Any. Puoi serializzare la class UsernameToken direttamente nella proprietà .Any e l’intestazione verrà aggiunta al messaggio. Ancora una volta, grazie per questa eccellente domanda.

    Come utilizzare il parametro SecurityHeader per aggiungere un’intestazione di sicurezza UsernameToken:

    Strumenti richiesti:

    Fiddler2 (o simile): non si riesce a capire nulla di questo senza ispezionare le intestazioni http.

    Riferimento richiesto:

     Microsoft.Web.Services3.dll -- you can reference this 2.0 framework assembly from your 4.0 assembly 

    Chiamata di servizio WCF:

     // Initialization of the service... _service = new MyService("MyEndpoint", RemoteUri); // etc. // Calling the service -- note call to GetSecurityHeader() _service.ServiceAction(GetSecurityHeader(), "myParam1"); // etc. ///  /// Construct the WSE 3.0 Security Header ///  private SecurityHeader GetSecurityHeader() { SecurityHeader h = new SecurityHeader(); UsernameToken t = new UsernameToken(RemoteLogin, RemotePassword, PasswordOption.SendPlainText); h.Any = new XmlElement[1]; h.Any[0] = t.GetXml(new XmlDocument()); return h; } 

    App.config:

                      

    Recentemente ho avuto un problema simile e ho smesso di cercare una soluzione non WSE. Dopo un paio di giorni in cui ho tirato fuori i capelli, ho finito di scaricare l’SDK WSE 3.0, di generare una class proxy usando WseWsdl3.exe e di creare una nuova politica per UsernameToken. Sono stato attivo e funzionante in 15 minuti. Al momento sta lavorando per me.

     RemoteService service = new RemoteService(); //generated class UsernameToken token = new UsernameToken(username, password, PasswordOption.SendPlainText); Policy policy = new Policy(); policy.Assertions.Add(new UsernameOverTransportAssertion()); service.SetClientCredential(token); service.SetPolicy(policy); var result = service.MethodCall();