2016-04-15 7 views
2

Wir verwenden Ping Federate, um zwei Webserver zu schützen (sowohl IIS als auch beide mit dem IIS-Integrationskit oder opentoken-Modul von Ping geschützt). Ein Server hostet eine WEB-API-Anwendung und der andere hostet eine Webseite. In der Web-API-Anwendung ist CORS aktiviert.Pingfederate opentoken-Modul CORS-Anfrage gibt 302 statt 200 zurück

Die Webseite macht Ajax Post-Anfragen mit JSON-Daten an den API-Server. Dies veranlasst den Browser, eine Preflight-Optionen-Anfrage zu initiieren. Auf dem API-Server fängt das Ping-Modul diese Anforderung ab, die keine Anmeldeinformationen enthält (die Spezifikationen sagen, dass Preflight-Optionsanforderungen keine Anmeldeinformationen enthalten sollen), und gibt eine 302-Umleitung zurück, bevor der Web-API-Code sie verarbeiten kann .

Meine einzige aktuelle Vermutung ist, ein benutzerdefiniertes Modul zu erstellen, das Optionenanforderungen verarbeitet und sie vor dem opentoken-Modul installiert. Gibt es andere mögliche/bessere Lösungen?

Antwort

1

Anstatt auf PING zu warten, habe ich einen IAuthorizationFilter auf den .NET Integration Kit/Agent gesetzt. Das Schöne an einem benutzerdefinierten Filter ist, dass Sie viel mehr Kontrolle über die Sicherheitsanforderungen Ihrer API-Endpunkte haben.

Wenn die Filter Schreiben I die folgenden Bezugszeichen verwendet:

  • http://www.asp.net/web-api/overview/security/authentication-filters
  • https://msdn.microsoft.com/en-us/magazine/dn781361.aspx

    opentoken verwendet; unter Verwendung von PF.SAML.Result; mit System; mit System.Collections.Generic; mit System.Configuration; mit System.Linq; mit System.Net.Http; mit System.Net.Http.Headers; mit System.Security.Claims; mit System.Text; mit System.Threading; mit System.Threading.Tasks; mit System.Web.Http.Filters;

    Namensraum PF.SAML.Filter { Öffentliche Klasse PingAuthenticationAttribute: IAuthenticationFilter { öffentliche bool AllowMultiple {get {return false; }}

    // http://www.asp.net/web-api/overview/security/authentication-filters 
        // https://msdn.microsoft.com/en-us/magazine/dn781361.aspx 
        public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken) 
        { 
         await Task.Run(() => { 
          /* 
          * Look for credentials in the request. 
          * If there are no credentials, do nothing and return (no-op). 
          * If there are credentials but the filter does not recognize the authentication scheme, do nothing and return (no-op). Another filter in the pipeline might understand the scheme. 
          * If there are credentials that the filter understands, try to authenticate them. 
          * If the credentials are bad, return 401 by setting context.ErrorResult. 
          * If the credentials are valid, create an IPrincipal and set context.Principal. 
          */ 
          var opentoken = context.Request.Headers.GetCookies() 
           .SelectMany(c => c.Cookies) 
           .Where(c => c.Name == "opentoken") 
           .FirstOrDefault(); 
    
          if(opentoken == null) return; 
    
          var userInfo = getOpenToken(opentoken.Value); 
    
          if(userInfo == null) { 
           context.ErrorResult = new AuthenticationFailureResult("Invalid Token", context.Request); 
           return; 
          } 
    
          var claims = new List<Claim>(); 
          foreach(var item in userInfo) { 
           foreach(var value in userInfo[item.Key]) { 
            claims.Add(new Claim(item.Key, value)); 
           } 
          } 
    
          var id = new ClaimsIdentity(claims, "opentoken"); 
          var principle = new ClaimsPrincipal(new[] { id }); 
    
          context.Principal = principle; 
    
         }); 
        } 
    
        public async Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken) 
        { 
         await Task.Run(() => { 
          var challenge = new AuthenticationHeaderValue("SAML"); 
          context.Result = new AddChallengeOnUnauthorizedResult(challenge, context.Result); 
         }); 
        } 
    
    
        private MultiStringDictionary getOpenToken(string token) 
        { 
         MultiStringDictionary attributes = null; 
    
         Configuration.Agent agentConfig = (Configuration.Agent) ConfigurationManager.GetSection("pfConfigurationGroup/agentConfiguration"); 
         AgentConfiguration config = new AgentConfiguration 
         { 
          CookieDomain = agentConfig.CookieDomain, 
          CookiePath = agentConfig.CookiePath, 
          NotBeforeTolerance = agentConfig.NotBeforeTolerance, 
          ObfuscatePassword = agentConfig.ObfuscatePassword, 
          RenewUntilLifetime = agentConfig.RenewUntilLifetime, 
          SecureCookie = agentConfig.SecureCookie, 
          SessionCookie = agentConfig.SessionCookie, 
          TokenLifetime = agentConfig.TokenLifetime, 
          TokenName = agentConfig.TokenName, 
          UseCookie = agentConfig.UseCookie, 
          UseSunJCE = agentConfig.UseSunJCE, 
          UseVerboseErrorMessages = agentConfig.UseVerboseErrorMessages 
         }; 
    
         var str = (config.ObfuscatePassword 
          ? Encoding.UTF8.GetString(Obfuscator.Deobfuscate(agentConfig.Password)) 
          : Encoding.ASCII.GetString(Convert.FromBase64String(agentConfig.Password))); 
         config.SetPassword(str, Token.CipherSuite.AES_128_CBC); 
    
         // TODO: Check for token expiration 
    
         Agent agent = new Agent(config); 
         attributes = agent.ReadTokenMultiStringDictionary(token); 
    
         return attributes; 
        } 
    } 
    

    }

+0

Ich habe meine Server kombiniert, um dieses Problem zu umgehen. Dies scheint der beste Weg zu sein, wenn PING keine Lösung anbietet, daher werde ich dies als eine Antwort markieren, aber es könnte sich ändern, wenn PING nützliche Informationen bereitstellt. – jp36

+0

Ich würde empfehlen, ein Beispiel für den von Ihnen erstellten Filter (wenn möglich) oder ein allgemeineres Filterbeispiel zu verwenden. StackOverflow missbilligt nur die Link-Antworten (Links könnten sterben, Informationen sind schwerer zu finden usw.). - Ein Beispiel bekommt eine Upvote! – jp36

0

Ist das ein Fehler bei der Implementierung des PING Federate IIS Agent/Integration Kits?

Ich stimme dem OP zu. Die aktuelle W3C-Empfehlung (https://www.w3.org/TR/cors/#preflight-request) sagt ausdrücklich zu schließen Sie Benutzeranmeldeinformationen in der Preflight/OPTIONS-Anfrage aus. Eine OPTIONS-Anfrage sollte daher eine anonyme Anfrage erlauben. Wenn man einen 302 zurück zum Identity Provider (IdP) ruft, sagt er mir, dass er der Empfehlung nicht folgt.


(Dies hilft nur auf dem PING-Server selbst, die Integrations-Kit muss noch anonym OPTIONS Anfragen ermöglichen.) Ping Federate kam mit mehr Konfigurationseinstellungen in der Anlegestelle Konfigurationsdatei:

<security-constraint> 
    <web-resource-collection> 
     <web-resource-name>Disable TRACE OPTIONS HEAD</web-resource-name> 
     <url-pattern>/*</url-pattern> 
     <http-method>TRACE</http-method> 
     <http-method>OPTIONS</http-method> 
    </web-resource-collection> 
    <auth-constraint/> 
</security-constraint> 
+0

ich denke, es Fehler sein kann. Ich warte darauf, von PING zu hören, um zu sehen, ob sie weitere Informationen zu diesem Problem haben. – jp36

Verwandte Themen