2017-07-16 6 views
1

Ich brauche SSO (Single Sign On) einen Benutzer von einer Anwendung von mir (Identity-Provider mit ASPNET Session State) und umleiten sie zu einer anderen Anwendung von mir (Service Provider), die konfiguriert ist zu verwenden impliziter Fluss mit IdentityServer4. Ich muss dies erreichen, ohne dass sich der Benutzer wieder anmelden muss und ohne das Passwort des Benutzers anzugeben.IdentityServer SSO - Vertrauenswürdige Anwendung

Mein erster Gedanke war, dass ich ein Client-Geheimnis für den Identitätsanbieter verwenden könnte den Benutzer auf IdentityServer4 Authentifizierung Endpunkt mit dem Zugriffstoken als Abfrageparameter zu umleiten und dann einen benutzerdefinierte Validator oder Erweiterung Zuschuss verwenden, um eine Identität zu erteilen Token zur Verwendung mit der Anwendung des Dienstanbieters, ohne dass auch das Kennwort des Benutzers angegeben werden muss.

Ich habe es geschafft, ein Zugriffs-Token an den Identity-Provider zu senden und dann den Benutzer zu IdentityServer4 umzuleiten, aber die Ausstellung eines Identitäts-Tokens hat sich als schwierig für mich erwiesen. Ich habe die Proben und die Dokumentation überflutet und bin gelinde gesagt verwirrt.

Ich bin auf der Suche nach Richtung auf den geeigneten Ansatz für dieses Szenario und vielleicht ein umfassendes Beispiel in C#. Ich verstehe, dass ich einen hybriden Fluss verwenden kann, um ein Zugangstoken sowie ein Identitäts-Token auszugeben. Ich denke, mein größter Kampf ist, wie man den Benutzer umleitet und basierend auf dem Zugriffstoken dem Benutzer ein Identitäts-Token ausstellt (und wenn dies sogar ein akzeptabler Ansatz ist).

Einfach ausgedrückt: Ich möchte den Benutzer von Anwendung A zu IdentityServer4 auf Anwendung B basierend auf Vertrauen mit dem Identity-Provider umleiten (über Client-Geheimnis?).

Hinweis: Ich verstehe, dass dies als eine meinungsbasierte Frage angesehen werden könnte, aber basierend auf meinen Untersuchungen glaube ich, dass es eine einzige Best Practice gibt und darum bitte ich.

Antwort

1

ich schaffte es, diese Funktion durch die folgende Strömung auslösen würde:

  1. Autorisieren Sie den Benutzer in Anwendung A (Identity Provider)
  2. Erhalten Sie Zugriffstoken von Identity Server 4 über Token Endpoint und Shared Secret.
  3. Fügen Sie Zugriffstoken als Abfragezeichenfolgenparameter hinzu, da die Header bei Umleitung nicht beibehalten werden.
  4. Leiten Sie den Benutzer zu einer Konto-Controller-Methode um, die Informationen wie den Benutzernamen akzeptiert. Diese Methode ist durch eine benutzerdefinierte Middleware-Klasse geschützt, die die Abfragezeichenfolge nach einem Zugriffstokenparameter überprüft. Wenn das Token vorhanden ist, wird es dem Authentifizierungsheader hinzugefügt. Dies autorisiert den Benutzer, diese Controller-Methode zu treffen.
  5. Die Controller-Methode wird den Benutzer dann unterschreiben und an den Endpunkt /connect/authorize/login umleiten.
  6. Schließlich legt der Anmeldeendpunkt das Cookie fest und leitet den Benutzer zur Anwendung B (Service Provider) um, dessen URL über den Abfrageparameter redirect_uri angegeben wird.

Konfiguration für Shared Secret:

entsprechenden Zuschuss Typen hinzufügen, geheime und neue Bereichsnamen an den Client. Der neue Bereich hilft beim Debuggen von Access-Token-Problemen in Ihren Protokollen (insbesondere wenn mehrere Anwendungen auf Ihren ID4-Server treffen). Stellen Sie außerdem sicher, dass Sie die URL des Dienstanbieters dem Client RedirectUris hinzufügen, andernfalls erhalten Sie eine Fehlermeldung "ungültige Weiterleitung".

  AllowedGrantTypes = new List<string> { GrantType.Implicit, GrantType.ClientCredentials }, 
      ClientSecrets = new List<Secret> { 
       new Secret(_clientSecrets.ExternalIdpSecret.Sha256(), clientID) 
      }, 
      AllowedScopes = new List<string> 
      { 
       "newScopeName" 
      }, 
      RedirectUris = new List<string> 
      { 
       $"http://localhost:<portnumber>" 
      } 

Als nächstes fügen Sie Ihre benutzerdefinierte Middleware hinzu.

public class QueryStringOAuthBearerMiddleware 
{ 
    private readonly RequestDelegate next; 

    public QueryStringOAuthBearerMiddleware(RequestDelegate next) 
    { 
     this.next = next; 
    } 

    public async Task Invoke(HttpContext context) 
    { 
     this.BeginInvoke(context); 
     await this.next.Invoke(context); 
     this.EndInvoke(context); 
    } 

    private void BeginInvoke(HttpContext context) 
    { 
     if (context.Request.Query.ContainsKey("accesstokenparametername")) 
     { 
      var accessToken = context.Request.Query.First(p => p.Key == "accesstokenparametername"); 

      if (!string.IsNullOrEmpty(accessToken.Value)) 
      { 
       context.Request.Headers.Add("Authorization", "Bearer " + accessToken.Value); 
      } 
     } 
    } 

    private void EndInvoke(HttpContext context) 
    { 
    } 
} 

Und fügen Sie die Middleware zu Ihrer Konfiguration hinzu.

 app.UseMiddleware<QueryStringOAuthBearerMiddleware>(); 

Erstellen Sie Ihre Login-Methode.

[HttpGet] 
    [Authorize] 
    public async Task<IActionResult> Login2(string userName, string returnURL) 
    { 
     await _httpContextWrapper.SignInAsync(userName); 

     return Redirect(returnURL); 
    } 

Konfiguration für Client-Anwendung (IDP):

Ihr Client-Seite Code sollte wie folgt aussehen:

var disco = await DiscoveryClient.GetAsync("http://localhost:<portnumber>"); 
var tokenClient = new TokenClient(disco.TokenEndpoint, "clientIdentifier", "IUsedAGuidHere"); 
var tokenResponse = await tokenClient.RequestClientCredentialsAsync("newScopeName"); 

var redirectURL = string.Format("http://localhost:2228/account/Login2?userName=<UserIDValue>&returnURL={1}&accesstokenparametername={0}", 
      tokenResponse.AccessToken, 
      Server.UrlEncode(
       string.Format("/connect/authorize/login?client_id={3}&redirect_uri={2}&response_type=id_token%20token&scope=<ImplicitFlowScopes>&state={0}&nonce={1}", 
       CryptoRandom.CreateUniqueId(), 
       CryptoRandom.CreateUniqueId(), 
       Server.UrlEncode("http://localhost:<PortNumber>"), 
       "ClientIdentifier"))); 

Response.Redirect(redirectURL, false); 

Hinweis: Bitte verstehen Sie, wird dies nicht nehmen der Lage sein, Code AS-IS und machen es funktioniert. Ich habe es stark modifiziert, um die Sicherheit meiner Ressourcen zu schützen.

+0

Haben die Anwendungen A und B in ihren * ClientSecrets * dasselbe * Secret *? @alan – Babak

+0

@Babak Anwendung B nutzt das ClientSecret nicht, da es sich um das OAuth-Token handelt. Einfach ausgedrückt: Anwendung A verwendet das ClientSecret, um das OAuth-Token zu erhalten, und stellt dieses Token anschließend Anwendung B. – alan

+0

Aber die Auth-App akzeptiert das Token nicht und lässt uns in Login2() gehen. Irgendeine Meinung? – Babak

0

ich glaube, ich Pflege der Authentifizierung zunächst mit Anwendung A nehmen könnte, dann nach vorne auf die nächste App ...

Anwendung A -> IdentityServer -> Anwendung A -> Anwendungs ​​B.

Sie könnten einige benutzerdefinierte Parameter in Ihrem returnUrl enthalten, die Anwendung A bei der Rückkehr von IdentityServer lesen konnte, die die Umleitung auf Anwendungs ​​B.

+0

Obwohl ich den Versuch zu schätzen weiß, haben Sie im Wesentlichen nur den Abschnitt "Simply put" meiner Frage neu formuliert. Ich habe selbst eine Lösung gefunden. – alan

Verwandte Themen