Catch-22 impedisce il servizio TCP WCF in streaming che può essere protetto da WIF; rovinando il mio Natale, la salute mentale


181

Ho un requisito per proteggere un endpoint del servizio WCF net.tcp in streaming tramite WIF . Dovrebbe autenticare le chiamate in arrivo sul nostro server token. Il servizio è trasmesso in streaming perché è progettato per trasferire grandi quantità di dati e roba.

Questo sembra impossibile. E se non riesco a aggirare il pescato, il mio Natale sarà rovinato e mi berrò a morte in una grondaia mentre gli acquirenti allegri calpestano il mio corpo che si raffredda lentamente. Totalmente seri, ragazzi.

Perché è impossibile? Ecco il Catch-22.

Sul client, devo creare un canale con GenericXmlSecurityToken che ottengo dal nostro server token. Nessun problema.

// people around here hate the Framework Design Guidelines.
var token = Authentication.Current._Token;
var service = base.ChannelFactory.CreateChannelWithIssuedToken(token);
return service.Derp();

Ho detto "no problemo"? Problemo. In effetti, NullReferenceExceptionstile problemo.

"Fratello", ho chiesto al Framework, "controlli anche nulla?" Il Framework era silenzioso, quindi l'ho smontato e l'ho scoperto

((IChannel)(object)tChannel).
    GetProperty<ChannelParameterCollection>().
    Add(federatedClientCredentialsParameter);

era la fonte dell'eccezione e che la GetPropertychiamata stava tornando null. Quindi, WTF? Si scopre che se accendo la sicurezza dei messaggi e imposto il tipo di credenziali del client su IssuedTokenallora questa proprietà esiste ora nel ClientFactory(protip: non esiste un equivalente "SetProperty" in IChannel, il bastardo).

<binding name="OMGWTFLOL22" transferMode="Streamed" >
    <security mode="Message">
        <message clientCredentialType="IssuedToken"/>
    </security>
</binding>

Dolce. Niente più NRE. Tuttavia, ora il mio cliente è in errore alla nascita (lo adoro ancora, comunque). Scavando attraverso la diagnostica WCF (protip: fai in modo che i tuoi peggiori nemici lo facciano dopo averli schiacciati e guidati davanti a te ma proprio prima di godere dei lamenti di donne e bambini), vedo che è a causa di una mancata corrispondenza di sicurezza tra server e client.

L'aggiornamento richiesto non è supportato da "net.tcp: // localhost: 49627 / MyService". Ciò potrebbe essere dovuto a associazioni non corrispondenti (ad esempio sicurezza abilitata sul client e non sul server).

Controllando i diag dell'host (di nuovo: schiaccia, guida, leggi i log, goditi i lamenti), vedo che è vero

Tipo di protocollo application / ssl-tls è stato inviato a un servizio che non supporta quel tipo di aggiornamento.

"Beh, io stesso", dico, "Attiverò la sicurezza dei messaggi sull'host!" E io faccio. Se vuoi sapere come appare, è una copia esatta della configurazione del client. Consultare.

Risultato: Kaboom.

L'associazione ('NetTcpBinding', ' http://tempuri.org/ ') supporta lo streaming che non può essere configurato insieme alla sicurezza a livello di messaggio. Prendi in considerazione la scelta di una modalità di trasferimento diversa o la sicurezza del livello di trasporto.

Pertanto, il mio host non può essere trasmesso in streaming e protetto tramite token . Prendi il 22.

tl; dr: come posso proteggere un endpoint WCF net.tcp in streaming usando WIF ???


3
Ok, probabilmente domanda ignorante qui, ma WIF richiede davvero la modalità Messaggio? La modalità di trasporto suona come se funzionasse meglio con lo streaming, qualcosa di evidentemente non testato<security mode="Transport" /> <transport clientCredentialType="IssuedToken" /> </security>
Joachim Isaksson

3
TransportWithMessageCredentialla modalità potrebbe essere un'altra opzione.
Joachim Isaksson,

3
TMLK, MessageSecurity è in grado di firmare e crittografare il payload bufferizzato, ma confonde quando si tratta di flussi. Hai preso in considerazione l'utilizzo di authenticationMode = IssuedTokenOverTransport?
OnoSendai,

7
Fammi vedere se posso evocare alcuni fantasmi del passato per aiutarti a salvare le tue vacanze allora. Alcuni suggerimenti qui: social.msdn.microsoft.com/Forums/vstudio/en-US/…
OnoSendai

2
Hai qualche possibilità di pubblicare un progetto di test case che altri potrebbero sperimentare?
antiduh

Risposte:


41

WCF ha problemi in alcune aree con streaming (ti sto guardando, MTOM 1 ) a causa di un problema fondamentale nel modo in cui non riesce a eseguire la pre-autenticazione nel modo in cui la maggior parte delle persone penserebbe che dovrebbe funzionare (influisce solo sulle richieste successive per quel canale , non la prima richiesta) Ok, quindi questo non è esattamente il tuo problema, ma per favore segui la procedura alla fine. Normalmente la sfida HTTP funziona in questo modo:

  1. il client colpisce il server in modo anonimo
  2. il server dice, scusa, 401, ho bisogno dell'autenticazione
  3. il client raggiunge il server con token di autenticazione
  4. il server accetta.

Ora, se si tenta di abilitare lo streaming MTOM su un endpoint WCF sul server, non si lamenterà. Ma quando lo configuri sul proxy client (come dovresti, devono corrispondere ai binding) esploderà in una morte infuocata. La ragione di ciò è che la sequenza di eventi sopra che WCF sta cercando di prevenire è questa:

  1. il client trasmette file da 100 MB al server in modo anonimo in un singolo POST
  2. il server dice scusa, 401, ho bisogno dell'autenticazione
  3. il client trasmette nuovamente il file da 100 MB al server con un'intestazione di autenticazione
  4. il server accetta.

Si noti che hai appena inviato 200 MB al server quando hai solo bisogno di inviare 100 MB. Bene, questo è il problema. La risposta è inviare l'autenticazione al primo tentativo, ma ciò non è possibile in WCF senza scrivere un comportamento personalizzato. Comunque sto divagando.

Il tuo problema

Prima di tutto, lascia che ti dica che ciò che stai provando è impossibile 2 . Ora, per smettere di far girare le ruote, lascia che ti dica perché:

Mi sembra che tu stia vagando in una simile classe di problemi. Se si abilita la sicurezza a livello di messaggio, il client deve caricare l'intero flusso di dati in memoria prima di poter effettivamente chiudere il messaggio con la solita funzione hash e la firma xml richiesta da ws-security. Se deve leggere l'intero flusso per firmare il singolo messaggio (che non è in realtà un messaggio, ma è un singolo flusso continuo), puoi vedere il problema qui. WCF dovrà trasmetterlo in streaming una volta "localmente" per calcolare la sicurezza dei messaggi, quindi trasmetterlo nuovamente per inviarlo al server. Questa è chiaramente una cosa sciocca, quindi WCF non consente la sicurezza a livello di messaggio per lo streaming di dati.

Pertanto, la semplice risposta qui è che è necessario inviare il token come parametro al servizio Web iniziale o come intestazione SOAP e utilizzare un comportamento personalizzato per convalidarlo. Non è possibile utilizzare WS-Security per fare ciò. Francamente, questo non è solo un problema WCF - non riesco a vedere come potrebbe praticamente funzionare per qualsiasi altra pila.

Risolvere il problema MTOM

Questo è solo per un esempio di come ho risolto il mio problema di streaming MTOM per l'autenticazione di base, quindi forse potresti prendere il coraggio e implementare qualcosa di simile per il tuo problema. Il punto cruciale è che per abilitare la finestra di ispezione dei messaggi personalizzata, è necessario disabilitare tutte le nozioni di sicurezza sul proxy client (rimane abilitato sul server), a parte il livello di trasporto (SSL):

this._contentService.Endpoint.Behaviors.Add(
    new BasicAuthenticationBehavior(
        username: this.Settings.HttpUser,
        password: this.Settings.HttpPass));
var binding = (BasicHttpBinding)this._contentService.Endpoint.Binding;
binding.Security.Mode = BasicHttpSecurityMode.Transport; // SSL only            
binding.Security.Transport.ClientCredentialType = 
   HttpClientCredentialType.None; // Do not provide

Si noti che ho disattivato la sicurezza dei trasporti qui perché fornirò a me stesso un ispettore dei messaggi e un comportamento personalizzato:

internal class BasicAuthenticationBehavior : IEndpointBehavior
{
    private readonly string _username;
    private readonly string _password;

    public BasicAuthenticationBehavior(string username, string password)
    {
        this._username = username;
        this._password = password;
    }
    public void AddBindingParameters(ServiceEndpoint endpoint, 
        BindingParameterCollection bindingParameters) { }
    public void ApplyClientBehavior(ServiceEndpoint endpoint,
        ClientRuntime clientRuntime)
    {
        var inspector = new BasicAuthenticationInspector(
            this._username, this._password);
        clientRuntime.MessageInspectors.Add(inspector);
    }
    public void ApplyDispatchBehavior(ServiceEndpoint endpoint,
        EndpointDispatcher endpointDispatcher) { }
    public void Validate(ServiceEndpoint endpoint) { }
}

internal class BasicAuthenticationInspector : IClientMessageInspector
{
    private readonly string _username;
    private readonly string _password;

    public BasicAuthenticationInspector(string username, string password)
    {
        this._username = username;
        this._password = password;
    }

    public void AfterReceiveReply(ref Message reply,
        object correlationState) { }

    public object BeforeSendRequest(ref Message request,
        IClientChannel channel)
    {
        // we add the headers manually rather than using credentials 
        // due to proxying issues, and with the 101-continue http verb 
        var authInfo = Convert.ToBase64String(
            Encoding.Default.GetBytes(this._username + ":" + this._password));

        var messageProperty = new HttpRequestMessageProperty();
        messageProperty.Headers.Add("Authorization", "Basic " + authInfo);
        request.Properties[HttpRequestMessageProperty.Name] = messageProperty;

        return null;
    }
}

Quindi, questo esempio è per chiunque soffra del problema MTOM, ma anche come scheletro per implementare qualcosa di simile per autenticare il token generato dal servizio token primario protetto da WIF.

Spero che questo ti aiuti.

(1) Dati di grandi dimensioni e streaming

(2) Sicurezza dei messaggi in WCF (vedere "svantaggi").


MTOM and Basic Authorizatione MTOM e OAuth2 ?
Kiquenet,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.