我已经创建了一个ASP。NET WebAPI项目,它使用基于声明的WIF身份验证。我还使用Thinktecture身份服务器,它托管在本地IIS上作为STS。在浏览器中一切正常;我被重定向到登录页面,可以在我的一个REST API控制器中看到Thread.CurrentPrincipal.Identity
中存在的正确标识。
我的问题是我不知道如何让一个活跃的客户端进行身份验证。我花了几个小时搜索和阅读,但还是没能奏效。就好像我的WebAPI根本不看HTTP报头。我尝试创建自己的IHttpModule来拦截请求,并可以在header中看到我的SAML令牌。我在客户端中得到的响应是登录页面,如果使用浏览器,用户通常会被重定向到该页面。我也尝试过这个问题中提到的所有方法。
我的活动客户端是这样的:
static void Main(string[] args)
{
string token = GetSamlToken();
CallService(token);
}
static Uri _baseAddress = new Uri("http://localhost:50565/");
static string _realm = "http://localhost:50565/";
private static string GetSamlToken()
{
var factory = new WSTrustChannelFactory(
new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential), "https://localhost/idsrv/issue/wstrust/mixed/username");
factory.TrustVersion = TrustVersion.WSTrust13;
factory.Credentials.UserName.UserName = "bob";
factory.Credentials.UserName.Password = "p@assword";
var rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
KeyType = KeyTypes.Bearer,
TokenType = TokenTypes.Saml2TokenProfile11,
AppliesTo = new EndpointReference(_realm)
};
System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
var token = factory.CreateChannel().Issue(rst) as GenericXmlSecurityToken;
return token.TokenXml.OuterXml;
}
private static void CallService(string token)
{
var client = new HttpClient
{
BaseAddress = _baseAddress
};
client.SetToken("SAML", token); //Constants.IdSrv.SamlScheme
while (true)
{
"Calling service.".ConsoleYellow();
var response = client.GetAsync("api/values").Result;
response.EnsureSuccessStatusCode();
var content = response.Content.ReadAsStringAsync();
content.Wait();
Console.WriteLine(content.Result);
Console.ReadLine();
}
}
我的网页的相关部分。配置如下:
<configuration>
<configSections>
<section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
<section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
</configSections>
<location path="FederationMetadata">
<system.web>
<authorization>
<allow users="*" />
</authorization>
</system.web>
</location>
<appSettings>
<add key="ida:FederationMetadataLocation" value="https://localhost/idsrv/FederationMetadata/2007-06/FederationMetadata.xml" />
<add key="ida:Issuer" value="https://localhost/idsrv/issue/wsfed" />
<add key="ida:ProviderSelection" value="productionSTS" />
</appSettings>
<system.web>
<authorization>
<deny users="?" />
</authorization>
<authentication mode="None" />
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true">
<remove name="FormsAuthentication" />
<add name="WSFederationAuthenticationModule" type="System.IdentityModel.Services.WSFederationAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
<add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
</modules>
<handlers>
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="WebDav" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%Microsoft.NETFrameworkv4.0.30319aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%Microsoft.NETFramework64v4.0.30319aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
<system.identityModel>
<identityConfiguration>
<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>
<audienceUris>
<add value="http://localhost:50565/" />
</audienceUris>
<certificateValidation certificateValidationMode="None" />
<claimsAuthorizationManager type="MvcApplication1.Claims.CustomAuthorizationManager, MvcApplication1" />
<issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry">
<authority name="http://identityserver.v2.thinktecture.com/samples">
<keys>
<add thumbprint="E590FF943557129F13F0DF618EC8B23B88983110" />
</keys>
<validIssuers>
<add name="http://identityserver.v2.thinktecture.com/samples" />
</validIssuers>
</authority>
</issuerNameRegistry>
</identityConfiguration>
</system.identityModel>
<system.identityModel.services>
<federationConfiguration>
<cookieHandler requireSsl="false" />
<wsFederation passiveRedirectEnabled="true" issuer="https://localhost/idsrv/issue/wsfed" realm="http://localhost:50565/" requireHttps="false" />
</federationConfiguration>
</system.identityModel.services>
</configuration>
我也添加了AuthenticationHandler
在我的WebApiConfig.cs像这样(基于此,也是我提到的其他SO问题):
var authentication = CreateAuthenticationConfiguration();
config.MessageHandlers.Add(new AuthenticationHandler(authentication));
private static AuthenticationConfiguration CreateAuthenticationConfiguration()
{
var authentication = new AuthenticationConfiguration
{
ClaimsAuthenticationManager = new ClaimsTransformer(),
RequireSsl = false,
EnableSessionToken = true
};
#region IdentityServer SAML
authentication.AddSaml2(
issuerThumbprint: "E590FF943557129F13F0DF618EC8B23B88983110",
issuerName: "https://localhost/idsrv/issue/wsfed",
audienceUri: "http://localhost:50565/",
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;
}
在我看来,就像WSFederationAuthenticationModule首先拦截请求,然后在AuthenticationHandler有机会寻找头中存在的SAML令牌之前重定向到STS登录。有人能看到我的配置有什么错误或缺失吗?
尝试删除
<authorization>
<deny users="?" />
</authorization>
来自系统。Web配置的Web部分。我对SAML不太确定,但我用JWT相对容易地实现了这一点,我认为对于基于REST的客户机,这是比SAML更好的选择。