我正在尝试“无配置 WIF”,我想接受由 Windows Azure 的 AppFabric STS 生成的 SAML2 token 。
我正在做的是解析检查当前请求的 token 信息,如下所示:
if (Request.Form.Get(WSFederationConstants.Parameters.Result) != null)
{
SignInResponseMessage message =
WSFederationMessage.CreateFromFormPost(System.Web.HttpContext.Current.Request) as SignInResponseMessage;
var securityTokenHandlers = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection();
XmlTextReader xmlReader = new XmlTextReader(
new StringReader(message.Result));
SecurityToken token = securityTokenHandlers.ReadToken(xmlReader);
if (token != null)
{
ClaimsIdentityCollection claims = securityTokenHandlers.ValidateToken(token);
IPrincipal principal = new ClaimsPrincipal(claims);
}
}
上面的代码使用了SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection();用于验证和处理 SAML token 的集合。但是:这不起作用,因为显然应用程序尚未正确配置。如何在我的 securityTokenHandlers 集合上以编程方式从 XML 指定以下配置?
<microsoft.identityModel>
<service>
<audienceUris>
<add value="http://www.someapp.net/" />
</audienceUris>
<federatedAuthentication>
<wsFederation passiveRedirectEnabled="true" issuer="https://rd-test.accesscontrol.appfabriclabs.com/v2/wsfederation" realm="http://www.thisapp.net" requireHttps="false" />
<cookieHandler requireSsl="false" />
</federatedAuthentication>
<applicationService>
<claimTypeRequired>
<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" optional="true" />
<claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" optional="true" />
</claimTypeRequired>
</applicationService>
<issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<trustedIssuers>
<add thumbprint="XYZ123" name="https://somenamespace.accesscontrol.appfabriclabs.com/" />
</trustedIssuers>
</issuerNameRegistry>
</service>
最佳答案
我也在努力解决同样的问题,并在 WIF 3.5/4.0 中找到了一个可行的解决方案。由于 maartenba 的链接似乎已失效,我想在这里发布我的解决方案。
我们的要求是:
- 完全在代码中进行配置(因为我们随应用提供了默认的 web.config)
- 允许的最大 .Net 版本 4.0(因此我使用 WIF 3.5/4.0)
我用什么来得出解决方案:
- 有关动态 WIF 配置的信息,由 Daniel Wu 提供 here .
- This method 在运行时注册 HTTP 模块,由 David Ebbo 解释。我 还尝试了更优雅的方法explained by Rick Strahl , 但不幸的是,这对我来说并没有成功。
Edit 2016/09/02: instead of adding a separate "pre application start code" class as in David Ebbo's example, the WIF-related HTTP modules can also be registered in the static constructor of the `HttpApplication' class. I have adapted the code to this somewhat cleaner solution.
我的解决方案在 web.config 中不需要任何内容。大部分代码位于 global.asax.cs 中。此示例中的配置是硬编码的:
using System;
using System.IdentityModel.Selectors;
using System.Security.Cryptography.X509Certificates;
using System.Web;
using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.Web;
namespace TestADFS
{
public class SessionAuthenticationModule : Microsoft.IdentityModel.Web.SessionAuthenticationModule
{
protected override void InitializePropertiesFromConfiguration(string serviceName)
{
}
}
public class WSFederationAuthenticationModule : Microsoft.IdentityModel.Web.WSFederationAuthenticationModule
{
protected override void InitializePropertiesFromConfiguration(string serviceName)
{
ServiceConfiguration = FederatedAuthentication.ServiceConfiguration;
PassiveRedirectEnabled = true;
RequireHttps = true;
Issuer = "https://nl-joinadfstest.joinadfstest.local/adfs/ls/";
Realm = "https://67px95j.decos.com/testadfs";
}
}
public class Global : HttpApplication
{
static Global()
{
Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(SessionAuthenticationModule));
Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(WSFederationAuthenticationModule));
}
protected void Application_Start(object sender, EventArgs e)
{
FederatedAuthentication.ServiceConfigurationCreated += FederatedAuthentication_ServiceConfigurationCreated;
}
internal void FederatedAuthentication_ServiceConfigurationCreated(object sender, Microsoft.IdentityModel.Web.Configuration.ServiceConfigurationCreatedEventArgs e)
{
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection coll = store.Certificates.Find(X509FindType.FindByThumbprint, "245537E9BB2C086D3C880982FA86267FBD66B9A3", false);
if (coll.Count > 0)
e.ServiceConfiguration.ServiceCertificate = coll[0];
store.Close();
AudienceRestriction ar = new AudienceRestriction(AudienceUriMode.Always);
ar.AllowedAudienceUris.Add(new Uri("https://67px95j.decos.com/testadfs"));
e.ServiceConfiguration.AudienceRestriction = ar;
ConfigurationBasedIssuerNameRegistry inr = new ConfigurationBasedIssuerNameRegistry();
inr.AddTrustedIssuer("6C9B96D90257B65B6F181C2478D869473DC359EA", "http://NL-JOINADFSTEST.joinadfstest.local/adfs/services/trust");
e.ServiceConfiguration.IssuerNameRegistry = inr;
e.ServiceConfiguration.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
}
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
FederatedAuthentication.WSFederationAuthenticationModule.ServiceConfiguration = FederatedAuthentication.ServiceConfiguration;
}
}
}
用法
我的应用程序是asp.net WebForms,以经典管道模式运行,支持表单例份验证以及ADFS登录。因此,身份验证是在所有 .aspx 页面共享的公共(public)基类中处理的:
protected override void OnInit(EventArgs e)
{
if (NeedsAuthentication && !User.Identity.IsAuthenticated)
{
SignInRequestMessage sirm = new SignInRequestMessage(
new Uri("https://nl-joinadfstest.joinadfstest.local/adfs/ls/"),
ApplicationRootUrl)
{
Context = ApplicationRootUrl,
HomeRealm = ApplicationRootUrl
};
Response.Redirect(sirm.WriteQueryString());
}
base.OnInit(e);
}
在此代码中,ApplicationRootUrl
是以“/”结尾的应用程序路径(“/”在经典管道模式中很重要)。
由于混合模式下注销的稳定实现并不那么容易,我也想展示其代码。从技术上讲它是有效的,但我在注销 ADFS 帐户后立即重新登录 IE 时仍然遇到问题:
if (User.Identity.IsAuthenticated)
{
if (User.Identity.AuthenticationType == "Forms")
{
FormsAuthentication.SignOut();
Session.Clear();
Session.Abandon();
ResetCookie(FormsAuthentication.FormsCookieName);
ResetCookie("ASP.NET_SessionId");
Response.Redirect(ApplicationRootUrl + "Default.aspx");
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
else
{
FederatedAuthentication.SessionAuthenticationModule.SignOut();
FederatedAuthentication.SessionAuthenticationModule.DeleteSessionTokenCookie();
Uri uri = new Uri(ApplicationRootUrl + "Default.aspx");
WSFederationAuthenticationModule.FederatedSignOut(
new Uri("https://nl-joinadfstest.joinadfstest.local/adfs/ls/"),
uri); // 1st url is single logout service binding from adfs metadata
}
}
(ResetCookie
是一个辅助函数,用于清除响应 cookie 并将其过期时间设置为过去)
关于model-view-controller - 从代码配置 Windows Identity Foundation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4916010/