2013-03-27 14 views
7

Wir verwenden ADFS für unsere internen Anwendungen - Benutzer sind grundsätzlich transparent angemeldet, wenn sie zu einer unserer Anwendungen gehen. Wenn jedoch ein Benutzer eine Seite offen über eine Stunde verläßt dann versucht, etwas auf dieser Seite zu tun (außer zu einer anderen Seite navigieren), erhalten sie einen Fehler:ADFS-Sitzung läuft ab und verursacht Fehler

This page is accessing information that is not under its control. This poses a security risk. Do you want to continue?

Es scheint, wie die Seite versucht, Umleiten dieser Anfrage an den ADFS-Server und das wird vom Browser verhindert.

Meine Frage lautet also: Wie kann ich diese Situation abfangen und den Benutzer dazu bringen, den ADFS-Server erneut zu authentifizieren?

Ich hatte noch nie etwas Glück bei Google diesbezüglich zu finden.

+0

Wenn es relevant ist, wenn Sie "Ja" drücken, um fortzufahren, bringt der Benutzer die Aktion - die nicht als ein GET existiert, so dass sie dann eine 404 bekommen. – zimdanen

+0

Haben Sie eine saubere Lösung gefunden? In unserem Fall denken wir darüber nach (wenn wir das Problem erkennen können), dass ein neuer (versteckter) iframe auf der Seite hinzugefügt wird, die auf eine neue Seite in der entsprechenden internen App zugreift. Das Laden dieser neuen Seite in den iframe sollte einen vollständigen passiven Fluss gegen den ADFS-Server auslösen, der nach der erneuten Authentifizierung die neue Seite schließlich lädt. Zu diesem Zeitpunkt wird die neue Seite die bestehende Seite darüber informieren, dass der Zyklus über 'postMessage 'abgeschlossen ist, und die entsprechenden Cookies sollten wieder verfügbar sein. –

+1

@Damien_The_Unbeliever: Wir haben wegen Zeitproblemen und anderer Prioritäten nicht weiter nachgedacht. Die iframe-Lösung fühlt sich hacky für mich an, aber wenn es der einzige Weg ist, das Problem zu beheben, ist es das, was es ist. Lassen Sie mich wissen, wie es für Sie funktioniert. – zimdanen

Antwort

1

Sie können Sicherheitstokens manuell in global.asax überprüfen und erneut ausgeben und damit gleitende Sitzungen erstellen. Bei gleitenden Sitzungen können Sie die Neuauthentifizierung aufschieben, bis dies "sicher" ist (wenn Daten aufgrund der ADFS-Weiterleitung nicht mehr verloren gehen).

Innerhalb des SessionSecurityTokenReceived-Ereignisses können Sie das Token und die Anforderung auswerten. Wenn das Token abgelaufen ist und die Anforderung einen Datenverlust durch eine Weiterleitung aufweist, können Sie ein neues "temporäres" Token erneut ausgeben. Das neue Token sollte eine sehr kurze Lebensdauer haben, nur so lange, dass Sie die aktuelle Anfrage sicher abschließen können. Das Token läuft dann ab und wird bei der nächsten Anfrage erneut ausgewertet.

protected void SessionAuthenticationModule_SessionSecurityTokenReceived(object sender, SessionSecurityTokenReceivedEventArgs e) 
{ 
    var now = DateTime.UtcNow; 
    SessionSecurityToken token = e.SessionToken; 
    var httpContext = new HttpContextWrapper(this.Context); 

    if (now > token.ValidTo 
     && (httpContext.Request.IsAjaxRequest() || httpContext.Request.HttpMethod == "POST")) 
    { 
     var sessionAuthModule = (SessionAuthenticationModule)sender; 
     e.SessionToken = sessionAuthModule.CreateSessionSecurityToken(token.ClaimsPrincipal, 
                    token.Context, 
                    now, 
                    now.AddMinutes(2), 
                    token.IsPersistent); 
     e.ReissueCookie = true; 
    } 
} 

Die ADFS-Sitzung wird die Neuauthentifizierung bis zur nächsten GET-Anforderung fortsetzen. Dann findet die Umleitung schließlich statt und dem Benutzer wird ein ordnungsgemäßes Token normaler Lebensdauer ausgestellt.

+0

Ich bin in der das gleiche Szenario der ersten Frage, und ich versuche diese Lösung. Welches nugget-Paket muss ich installieren? Dieser Handler wird nie ausgelöst. –

+0

Dies verwendet das Microsoft Token Validation Extension-Paket (System.IdentityModel.Tokens.ValidatingIssuerNameRegistry). – friggle

3

Update: Die folgende Lösung hängt von iframes ab. In ADFS 3.0 sind X-Frame-Optionen standardmäßig auf DENY eingestellt, wobei die Einstellung nicht geändert werden kann. Diese Lösung funktioniert nur mit ADFS 2.1 & früher.

In Ihrer global.asax.cs wollen Sie alle Mid-AJAX 302er fangen und sie in einen 401 Unauthorized verwandeln. Dadurch wird verhindert, dass der Aufruf fortgesetzt wird (und diese Nachricht ausgegeben wird), und wir werden an $ (document) .ajaxError() gesendet.

protected void Application_EndRequest() 
    { 
     var context = new HttpContextWrapper(this.Context); 
     if (context.Response.StatusCode == 302 && context.Request.IsAjaxRequest()) 
     { 
      context.Response.Clear(); 
      context.Response.StatusCode = 401; 
     } 
    } 

Dann, dort abfangen alle 401S, bevor sie an den Rest Ihres Fehlerbehandlung fortzufahren. Ich entschied mich, den Benutzern eine Nachricht zu zeigen. Sie können den nächsten Schritt hier machen, aber zur besseren Lesbarkeit sende ich das ajaxSettings-Objekt an eine andere Funktion. Geben Sie true zurück, damit es nicht in den Rest der Fehlerbehandlung geht.

Wenn Sie überprüfen möchten, ob dies ADFS ist, wird event.target.referrer die URL der versuchten Weiterleitung haben.

$(document).ajaxError(function (event, jqXHR, ajaxSettings, thrownError) { 
    if (xhr.status == 401) { 
     alert("Your session has timed out. Click OK to reauthorize and extend your session."); 

     TriggerReauthenticationRefresher(ajaxSettings); 
     return true; 
    } 
…the rest of the error handling code…    
}); 

Ich habe eine leere div in meiner Seite nur für diese Situation, mit der id ‚refresherBox‘, aber Sie können dies in Ihrem DOM auf ein beliebiges Element tun. Stellen Sie einen Iframe zusammen, der zu einer Dummy-Seite in Ihrer Domain führt. In meinem Fall sind die Inhalte von ADFSRefresher.cshtml nur

<div><input type="hidden" value="@DateTime.Now.ToString()" /></div> 

Stattdessen globale Variablen verwenden, ich bin Speichern der ajaxSettings mit .data(). Wir müssen auch verfolgen, wie oft der iFrame neu geladen wird, also speichern wir auch den Ladezähler. Fügen Sie den iframe in das DOM ein und es wird gestartet.

TrackFrameReloads wird jedes Mal ausgelöst, wenn der Iframe geladen wird. Da wir wissen, dass eine ADFS-Weiterleitung bevorsteht, wird sie zweimal ausgelöst. Das erste Mal wird die Umleitung sein, und das zweite Mal wird es sein src URL. Beim ersten Mal erhöhen wir nur den Ladezähler.

Das zweite Mal, wenn es ausgelöst wird, wissen wir, dass wir erfolgreich erneut authentifiziert wurden. Rufen Sie die Ajax-Einstellungen ab, löschen Sie die gespeicherten Daten, und Sie können Ihre ursprünglichen Einstellungen erneut verwenden, um den AJAX-Anruf zu senden! Es wird durchlaufen, nicht umgeleitet und seinen ursprünglichen Erfolg & komplette Funktionen ausführen.

function TrackFrameReloads() { 
    var i = $('#refresherBox').data('loadcount'); 
    if (i == 1) { 
     alert('Your session has been extended.'); 

     var ajaxSettings = $('#refresherBox').data('originalRequestSettings'); 

     $('#refresherBox').removeData(); 

     $.ajax(ajaxSettings); 

    } else { 
     $('#refresherBox').data("loadcount", 1); 
    } 
} 

Beachten Sie, dass der Fehler und die vollständigen Funktionen bereits ausgelöst wurden, wenn Sie sie definiert haben

Sie können die zwei Warnmeldungen an die Benutzer überspringen, wenn Sie möchten.Abhängig von Ihrem ADFS-Setup sollte dies nur 1 Sekunde dauern und der Benutzer muss nicht darüber informiert werden, dass dies überhaupt passiert ist!

+0

Das funktioniert, aber ich habe das Gefühl, dass es besser wäre, früher in der Anfrage zu erfahren, dass die Sitzung abgelaufen ist, und dann etwas zu tun, anstatt all deine 302 Antworten zu können. – BigOmega

+0

ADFS erlaubt mir nicht, in einen iFrame zu laden entweder: Weigerte sich, in einem Rahmen anzuzeigen, weil es "X-Frame-Optionen" auf "DENY" gesetzt. Irgendwo herum? – severin

+1

Wissen Sie, welche Version von ADFS es ist? Anscheinend setzt ADFS 3 die Einstellung auf DENY und bietet keine Möglichkeit, sie zu ändern. Ich werde meine Antwort aktualisieren, um festzustellen, dass diese Lösung nur mit ADFS 2 und höher funktioniert. Ich bin tatsächlich von der Verwendung der veröffentlichten Lösung abgerückt und habe stattdessen begonnen, Gleitsitzungen zu verwenden. Dieser Beitrag war sehr hilfreich für das Lernen darüber: http://www.cloudidentity.com/blog/2010/06/16/warning-sliding-sessions-are-closer-than-they-appear/ – friggle