Authentifizieren einer Anforderung von einer C # -Anwendung bei einer WIF-fähigen ASP.NET-WebApi-Anwendung mithilfe einer SAML-Zusicherung

Ich habe den ThinkTecture-Identitätsserver als STS eingerichtet, ein Web-API-Projekt eingerichtet und das Tool "Identität und Zugriff" in Visual Studio verwendet und auf meine Verbundmetadaten verwiesen, um die Verbundauthentifizierung über WIF zu ermöglichen. So sieht der zugehörige Teil von web.config aus:

<system.identityModel>
    <identityConfiguration saveBootstrapContext="true">
      <audienceUris>
        <add value="http://localhost:41740/" />
      </audienceUris>

    <securityTokenHandlers>
        <add type="System.IdentityModel.Tokens.SamlSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
        <add type="System.IdentityModel.Tokens.Saml2SecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
    </securityTokenHandlers>            

      <issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry">
        <authority name="http://auth.myserver.com/samples">
          <keys>
            <add thumbprint="F89C10B505E015774D02E323DEDA32878F794028" />
          </keys>
          <validIssuers>
            <add name="http://auth.myserver.com/samples" />
          </validIssuers>
        </authority>
      </issuerNameRegistry>
      <!--certificationValidationMode set to "None" by the the Identity and Access Tool for Visual Studio. For development purposes.-->
      <certificateValidation certificateValidationMode="None" />
    </identityConfiguration>
  </system.identityModel>
  <system.identityModel.services>
    <federationConfiguration>
      <cookieHandler requireSsl="false" />
      <wsFederation passiveRedirectEnabled="true" issuer="https://10.40.40.68/issue/wsfed" realm="http://localhost:41740/" requireHttps="false" />
    </federationConfiguration>
  </system.identityModel.services>

Dies eignet sich hervorragend zur Authentifizierung von Benutzern, die die API über den Browser verwenden.

Ich muss jetzt die gleiche API von Code (C #) in einer Client-Anwendung aufrufen - lassen Sie uns diesen APIClient aufrufen - mit HTTPClient.

Dazu habe ich diese in die web.config eingefügt:

<securityTokenHandlers>
        <!--<add type="System.IdentityModel.Tokens.JwtSecurityTokenHandler, System.IdentityModel.Tokens.Jwt" />-->
        <add type="System.IdentityModel.Tokens.SamlSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
        <add type="System.IdentityModel.Tokens.Saml2SecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
</securityTokenHandlers>

Ich ging davon aus, dass WIF die Anforderung aufnimmt und authentifiziert, wenn ich den SAML-Token-Handler hinzufüge und eine SAML-Zusicherung zum HTTP-Authorize-Header hinzufüge.

Ich kann den STS aufrufen, um ein SAML-Token abzurufen, wie in der GetSamlToken-Methode hier beschrieben:Geben Sie hier die Linkbeschreibung ein

Das gibt mir eine SAML-Aussage, die ich an den HTTPClient-Header anhänge:

client.SetToken("SAML", AuthenticationHeader);

WoherAuthenticationHeader ist die SAML-Zusicherung, die ich vom Server erhalten habe. Das Problem ist, dass die Web-API mit der Samle-Behauptung nichts zu tun hat - als ob sie es nicht einmal sehen würde. Alles, was ich als Antwort bekomme, ist eine Umleitung zum STS.

Was mache ich falsch? Wie kann ich meine geschützte Web-API-Methode von einem anderen Code aus authentifizieren und aufrufen, ohne zu JWT usw. wechseln zu müssen?

Vielen Dank im Voraus für Ihre Hilfe!

-- aktualisierte

Ich habe meiner WebApiConfig.cs Folgendes als @Brock vorgeschlagen hinzugefügt:

public static void Register(HttpConfiguration config)
{
    // Cross Origin Resource Sharing
    //CorsConfig.RegisterCors(GlobalConfiguration.Configuration);
    CorsConfig.RegisterCors(config);


    //CorsConfiguration corsConfig = new CorsConfiguration();
    //corsConfig.AllowAll();
    //var corsHandler = new CorsMessageHandler(corsConfig, config);
    //config.MessageHandlers.Add(corsHandler);


    // authentication configuration for identity controller
    var authentication = CreateAuthenticationConfiguration();
    config.MessageHandlers.Add(new AuthenticationHandler(authentication));



    // ASP.Net web api uses NewtonSoft Json.net natively, 
    // the following line forces the web api to use the xml serializer instead of data contract serializer
    config.Formatters.XmlFormatter.UseXmlSerializer = true;

    log.Debug("Registering Web API Routes");


    // register api routes

}




private static AuthenticationConfiguration CreateAuthenticationConfiguration()
{
    var authentication = new AuthenticationConfiguration
    {
        ClaimsAuthenticationManager = new ClaimsTransformer(),
        RequireSsl = false,
        EnableSessionToken = true
    };

    #region IdentityServer SAML
    authentication.AddSaml2(
        issuerThumbprint: "F89C10B505E015774D02E323DEDA32878F794028",
        issuerName: "https://10.40.40.68/issue/wsfed",
        audienceUri: "http://localhost:41740/",//Constants.Realm,
        certificateValidator: System.IdentityModel.Selectors.X509CertificateValidator.None,
        options: AuthenticationOptions.ForAuthorizationHeader("SAML"),
        scheme: AuthenticationScheme.SchemeOnly("SAML"));
    #endregion

    #region Client Certificates
    authentication.AddClientCertificate(ClientCertificateMode.ChainValidation);
    #endregion

    return authentication;
}

Allerdings bekomme ich immer noch eine 302 Antwort. So stelle ich die Anfrage:

ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;


var factory = new WSTrustChannelFactory(
    new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
    "https://10.40.40.68/issue/wstrust/mixed/username");
factory.TrustVersion = TrustVersion.WSTrust13;

factory.Credentials.UserName.UserName = "myusername";
factory.Credentials.UserName.Password = "password";

var rst = new RequestSecurityToken
{
    RequestType = RequestTypes.Issue,
    KeyType = KeyTypes.Bearer,
    TokenType = Thinktecture.IdentityModel.Constants.TokenTypes.Saml2TokenProfile11,
    AppliesTo = new EndpointReference("http://localhost:41740/")
};

var token = factory.CreateChannel().Issue(rst) as System.IdentityModel.Tokens.GenericXmlSecurityToken;

string myToken = token.TokenXml.OuterXml;

HttpClient client = new HttpClient(new HttpClientHandler
{
    ClientCertificateOptions = ClientCertificateOption.Automatic,
    AllowAutoRedirect = false
});

client.SetToken("SAML", myToken);
//client.SetBearerToken(myToken);

var resp = client.GetAsync("http://localhost:41740/api/clients", HttpCompletionOption.ResponseContentRead).Result;
Assert.IsTrue(resp.IsSuccessStatusCode);

Antworten auf die Frage(1)

Ihre Antwort auf die Frage