asp.net-core - Okta 和 Sustainsys.SAML2 的 AuthenticateResult.Succeeded 为假
问题描述
我有一个利用 Sustainsys.Saml2.AspNetCor2 (2.7.0) 的 .Net Core 2 应用程序。前端是一个 Angular 应用程序。我采用的 SAML 方法基于并且非常类似于此参考实现中采用的方法:https ://github.com/hmacat/Saml2WebAPIAndAngularSpaExample
*测试 IDP ( https://stubidp.sustainsys.com ) 一切正常。
但是当我们尝试与 Okta 集成时,回调方法(见下文)中的 AuthenticateResult.Succeeded 属性始终为 false,即使发布到 ASC 端点的 SAML 似乎表明身份验证成功。我们根本没有看到任何错误。它只是没有成功。
(请注意,我的公司无法访问 Okta - 这是由合作伙伴公司维护的。)
这是控制器中的服务器代码:
[AllowAnonymous]
[HttpPost, HttpGet]
[Route("api/Security/InitiateSamlSingleSignOn")]
public IActionResult InitiateSamlSingleSignOn(string returnUrl)
{
return new ChallengeResult(
Saml2Defaults.Scheme,
new AuthenticationProperties
{
RedirectUri = Url.Action(nameof(SamlLoginCallback), new { returnUrl })
});
}
[AllowAnonymous]
[HttpPost, HttpGet]
[Route("api/Security/SamlLoginCallback")]
public async Task<IActionResult> SamlLoginCallback(string returnUrl)
{
var authenticateResult = await HttpContext.AuthenticateAsync(ApplicationSamlConstants.External);
if (!authenticateResult.Succeeded)
{
return Unauthorized();
}
// more code below, never reached
}
这是 Okta 发送的一些 SAML 的屏幕截图,使用 Chrome 扩展程序 SAML-tracer 捕获:
我不知道如何进一步调查。非常感激任何的帮助!
在 ConfigureServices 方法中,如果它有用,我有以下(在相关部分):
public void ConfigureServices(IServiceCollection services)
{
// [snip]
if (usingSAML)
{
services.Configure<CookiePolicyOptions>(options =>
{
// SameSiteMode.None is required to support SAML SSO.
options.MinimumSameSitePolicy = SameSiteMode.None;
options.CheckConsentNeeded = context => false;
// Some older browsers don't support SameSiteMode.None.
options.OnAppendCookie = cookieContext => SameSite.CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
options.OnDeleteCookie = cookieContext => SameSite.CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
});
authBuilder = services.AddAuthentication(o =>
{
o.DefaultScheme = ApplicationSamlConstants.Application;
o.DefaultSignInScheme = ApplicationSamlConstants.External;
o.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
});
authBuilder.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
// see https://stackoverflow.com/questions/46243697/asp-net-core-persistent-authentication-custom-cookie-authentication
options.ExpireTimeSpan = new System.TimeSpan(365, 0, 0, 0, 0);
options.AccessDeniedPath = new PathString("/login");
options.LoginPath = new PathString("/login");
})
.AddCookie(ApplicationSamlConstants.Application)
.AddCookie(ApplicationSamlConstants.External)
.AddSaml2(options =>
{
options.SPOptions.EntityId = new EntityId(this.Configuration["Saml:SPEntityId"]);
options.IdentityProviders.Add(
new IdentityProvider(
new EntityId(this.Configuration["Saml:IDPEntityId"]), options.SPOptions)
{
MetadataLocation = this.Configuration["Saml:IDPMetaDataBaseUrl"],
LoadMetadata = true,
});
options.SPOptions.ServiceCertificates.Add(new X509Certificate2(this.Configuration["Saml:CertificateFileName"]));
});
}
// [snip]
}
更新:我修改了代码以捕获更多日志记录信息,我发现,在 Saml2/Acs 端点,用户正在接受身份验证。在日志文件中,我看到:
2020-09-14 09:28:09.307 -05:00 [DBG] Signature validation passed for Saml Response Microsoft.IdentityModel.Tokens.Saml2.Saml2Id
2020-09-14 09:28:09.369 -05:00 [DBG] Extracted SAML assertion id1622894416505593469999142
2020-09-14 09:28:09.385 -05:00 [INF] Successfully processed SAML response Microsoft.IdentityModel.Tokens.Saml2.Saml2Id and authenticated bankoetest@sfi.cloud
但是,当我使用 SamlLoginCallback 方法时,此调用获得的 AuthenticateResult 中不存在此身份验证信息:
var authenticateResult = await HttpContext.AuthenticateAsync(ApplicationSamlConstants.External);
我的身份验证结果对象的自定义日志记录信息如下所示:
2020-09-14 09:28:09.432 -05:00 [ERR] SAML Authentication Failure: authenticateResult.Failure (Exception object) is null;
No information was returned for the authentication scheme;
authenticateResult.Principal is null;
authenticateResult.Properties is null.
authenticateResult.Ticket is null.
可能出了什么问题?
解决方案
这里的根本原因最终是 Okta 使用的 Url 与我们在重定向逻辑中的代码不同的结果。URL 匹配,但案例不匹配。这导致后来调用的方法无法读取 cookie,这些方法被发送到不同的 URL,即使不同之处仅在于路径的大小写。一旦我们确保所有路径都完全匹配,直到外壳,它就开始工作了。
推荐阅读
- python - 如何将数据框中的列转换为python中的嵌套字典?
- perl - 在 Perl 的给定目录中替换字符串(文件名)
- javascript - 在不知道密钥的情况下渲染表格
- algorithm - 在决策树中计算熵
- ms-access-2016 - 如何在子表单中显示相关表中的字段?
- nginx-ingress - 无法为 AKS 中托管的 mendix 应用程序路由入口。入口始终路由到默认后端或路径为 / 的服务
- javascript - 如何使用 Javascript 使用所有应用的 css 样式打印特定 div 内的内容?
- machine-learning - 如何检测感知器算法的错误次数
- c# - 使用 C# 获取 Uniswap V3 LP 头寸的“未收取费用”
- android - 使用警报对话框时在回收站视图中从 Firebase 中删除项目