我有一个新的.Net Core Razor应用程序,该应用程序使用本地登录名,我正在尝试使用我们公司的IDP(来自Computer Associates的SAML2服务)添加联合身份验证。 IDP不提供MetadabaseAddress,因此我必须手动配置所有内容。我能够单击新的“登录”按钮,并重定向到IDP的登录页面,登录后,我将重定向到我的应用程序的“登录-wsfed”页面,但是出现了“无消息”错误
我已将错误的源归结为WsFederationHandler.cs类here,看来该处理程序无法找到saml令牌,但是,使用浏览器的开发人员工具,我可以看到表单数据包含令牌(看起来像是基数为64的字符串)。
这是我的代码:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
// Password settings for local accounts
options.Password.RequireDigit = true;
options.Password.RequiredLength = 8;
options.Password.RequiredUniqueChars = 2;
options.Password.RequireLowercase = true;
options.Password.RequireNonAlphanumeric = true;
options.Password.RequireUppercase = true;
options.User.RequireUniqueEmail = true;
options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@!$";
})
.AddEntityFrameworkStores<ApplicationContext>()
.AddDefaultTokenProviders();
// Creating the configuration object for WsFederation so we can access more settings
// This is used in lieu of retrieving the MetadataBase xml file from the IDP
var wsfConfig = new WsFederationConfiguration
{
TokenEndpoint = Configuration.GetValue<string>("MyAccess:TokenEndpoint"), // This is where the user gets redirected to, provided by the MyAccess team. Example: https://federatetest.smext.faa.gov/affwebservices/public/saml2sso?SPID=https://training.amc.faa.gov
Issuer = Configuration.GetValue<string>("MyAccess:Issuer") // This is the entityId from the settings Xml file, typically the URI of the application
};
// Add the certificate that will be used by the IDP to sign (encrypt) the token; this way we know how to decrypt the token
// The cert is a base64 encoded string
wsfConfig.SigningKeys.Add(new X509SecurityKey(new X509Certificate2(Convert.FromBase64String(Configuration.GetValue<string>("MyAccess:Certificate")))));
services.AddAuthentication(authOptions =>
{
authOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
authOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
authOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
})
.AddWsFederation(WsFederationDefaults.AuthenticationScheme, "My Access", options =>
{
options.Configuration = wsfConfig;
options.Wreply = Configuration.GetValue<string>("MyAccess:Reply");
options.Wtrealm = Configuration.GetValue<string>("MyAccess:Realm");
options.TokenValidationParameters.NameClaimType = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress";
//options.SkipUnrecognizedRequests = true;
// Uncomment if IDP requires a wct value
//options.Events.OnRedirectToIdentityProvider = context =>
// {
// context.ProtocolMessage.Wct = DateTimeOffset.UtcNow.ToString();
// return Task.CompletedTask;
// };
})
.AddCookie();
//Configure D I
services.AddScoped<IEmployeeStore, EmployeeStore>();
services.AddScoped<IDepartmentStore, DepartmentStore>();
// Configure additional services
services.AddMvc();
// Adds a default in-memory implementation of IDistributedCache.
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
// Set the session timeout
options.IdleTimeout = TimeSpan.FromMinutes(45);
options.Cookie.Name = ".EmployeeTracker.Session";
});
// This is where we define our authorization policies
services.AddAuthorization(options =>
{
options.AddPolicy("EmployeeViewer", policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireClaim("Role", "admin");
});
});
services.ConfigureApplicationCookie(options =>
{
// Cookie settings
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(45);
options.LoginPath = "/Login/Login";
options.SlidingExpiration = true;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, UserManager<ApplicationUser> userManager)
{
GlobalDiagnosticsContext.Set("configDir", Configuration.GetSection("AppSettings")["NLogDir"]);
GlobalDiagnosticsContext.Set("connectionString", Configuration.GetConnectionString("DefaultConnection"));
if (env.IsDevelopment())
{
// Only enable BrowserLink if it's really needed. It's a resource hog.
//app.UseBrowserLink();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// Configure security settings
app.UseXContentTypeOptions(); // sets the X-Content-Type-Options to no-sniff
app.UseReferrerPolicy(opts => opts.NoReferrer());
app.UseXXssProtection(options => options.EnabledWithBlockMode());
app.UseXfo(options => options.Deny()); // Block iframes
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts(hsts => hsts.MaxAge(1).IncludeSubdomains());
}
// Configure middleware
app.UseAuthentication();
app.UseStaticFiles();
app.UseStatusCodePagesWithReExecute("/Status{0}"); // Status403.cshtml, Status404.cshtml, etc.
app.UseCookiePolicy();
app.UseSession();
app.UseMvc();
}
}
由于我必须手动配置事物,因此会遗漏一些东西。另外,只是为了证实我的怀疑,我在SkipUnrecognizedRequests中添加了该选项,并得到了另一个错误。
TIA,为您提供任何帮助。