无法使用Sustainsys中的Saml2注销



这应该是将我的应用程序重定向到我的AdFs signOut页面,然后将我重定向回我的应用。然而,它只是将我重定向到我的路线"/注销"。在我的ADFS服务器上查看日志时,什么也没发生。

[AllowAnonymous]
[HttpGet]
[Route("api/logout")]
public async Task<IActionResult> Logout()
{
return SignOut(new AuthenticationProperties()
{
RedirectUri = "/logout"
},
Saml2Defaults.Scheme);
}

SignIn运行良好。我甚至尝试过同样的方法,但都不起作用。这里,ReturnUrl方法从HttpContext获取位置。回答头球当我尝试注销时,位置总是空的。

[AllowAnonymous]
[HttpGet]
[Route("api/login")]
public async Task<string> LoginAdfs()
{
string redirectUri =  _appSettings.Saml.SpEntityId;
await HttpContext.ChallengeAsync(new AuthenticationProperties
{
RedirectUri = string.Concat(redirectUri, "/autenticado")
});
return ReturnUrl();
}

知道会发生什么吗?

更新21/11/2019

事实证明,Saml2Handler根本没有试图将请求发送到服务器。我在我的输出窗口上收到这些消息:

Sustainsys.Saml2.AspNetCore2.Saml2Handler: Debug: Initiating logout, checking requirements for federated logout
Issuer of LogoutNameIdentifier claim (should be Idp entity id): 
Issuer is a known Idp: False
Session index claim (should have a value): 
Idp has SingleLogoutServiceUrl: 
There is a signingCertificate in SPOptions: True
Idp configured to DisableOutboundLogoutRequests (should be false): 
Sustainsys.Saml2.AspNetCore2.Saml2Handler: Information: Federated logout not possible, redirecting to post-logout

这是我的启动配置,我不明白这里出了什么问题:

ServiceCertificate se = new ServiceCertificate()
{
Certificate = new X509Certificate2(SpCert, "",X509KeyStorageFlags.MachineKeySet),
Use = CertificateUse.Signing
};
SPOptions sp = new SPOptions
{
AuthenticateRequestSigningBehavior = SigningBehavior.Never,
EntityId = new EntityId(SpEntityId),
ReturnUrl = new Uri("/login"),
NameIdPolicy = new Sustainsys.Saml2.Saml2P.Saml2NameIdPolicy(null, Sustainsys.Saml2.Saml2P.NameIdFormat.Unspecified),
};
sp.ServiceCertificates.Add(se);
IdentityProvider idp = new IdentityProvider(new EntityId(appSettings.Saml.EntityId), sp);
idp.Binding = Saml2BindingType.HttpPost;
idp.AllowUnsolicitedAuthnResponse = true;
//idp.WantAuthnRequestsSigned = true;
idp.SingleSignOnServiceUrl = new Uri("/login");
//idp.LoadMetadata = true;
idp.SigningKeys.AddConfiguredKey(new X509Certificate2(IdpCert));
idp.MetadataLocation = theMetadata;
idp.DisableOutboundLogoutRequests = true;

要想注销,用户需要有两个特殊的声明"LogoutNameIdentifier"one_answers"SessionIndex"(全名为http://Sustainsys.se/Saml2/LogoutNameIdentifierhttp://Sustainsys.se/Saml2/SessionIndex(。这些声明携带Saml2库注销所需的当前会话信息。

现在我没有看到你的整个启动,所以我无法理解你的应用程序的流程。但这些声明应该存在于库返回的身份中——可能存储在外部cookie中(如果您使用的是asp.net身份(。当您的应用程序设置应用程序cookie时,这两个声明必须转移到会话标识中。

此外,您实际上已经使用DisableOutboundLogoutRequests禁用了出站注销。但这并不是主要问题,因为您的日志表明不存在所需的索赔。

根据我自己的经验,Anders Abel提到的这两个声明应该出现在用户身上。我没有看到这些索赔,直到我通过了所有索赔和登录请求。ASP。NET Core在SignInAsync上重新创建主体,并且需要声明与请求一起传入。

通过以下操作,我可以使用我的服务完成SingleLogout:

await HttpContext.SignInAsync(user.SubjectId, user.Username, props, user.Claims.ToArray());

经过一段时间的努力,以下是作为Saml2WebAPIAndAngularSpaExample的扩展实现注销功能的代码(请参阅https://github.com/hmacat/Saml2WebAPIAndAngularSpaExample)。

启动.cs

builder.Services.AddAuthentication(o =>
{
o.DefaultScheme = ApplicationSamlConstants.Application;
o.DefaultSignInScheme = ApplicationSamlConstants.External;
o.DefaultAuthenticateScheme = ApplicationSamlConstants.Application; //needed for logout
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ClockSkew = TimeSpan.FromMinutes(Convert.ToDouble(builder.Configuration["Jwt:ExpireInMinutes"])),
ValidIssuer = builder.Configuration["Jwt:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])),
};
})
.AddCookie(ApplicationSamlConstants.Application)
.AddCookie(ApplicationSamlConstants.External)
.AddSaml2(options =>
{
options.SPOptions.EntityId = new EntityId(builder.Configuration["Saml:SPEntityId"]);
var idp = new IdentityProvider(new EntityId(builder.Configuration["Saml:IDPEntityId"]), options.SPOptions)
{
Binding = Saml2BindingType.HttpPost,
SingleSignOnServiceUrl = new Uri(builder.Configuration["Saml:IDPSingleSignOnServiceUrl"]),
SingleLogoutServiceBinding = Saml2BindingType.HttpRedirect,
SingleLogoutServiceUrl = new Uri(builder.Configuration["Saml:IDPSingleLogoutServiceUrl"]),
AllowUnsolicitedAuthnResponse = true,
DisableOutboundLogoutRequests = false,
//LoadMetadata = false
};
idp.SigningKeys.AddConfiguredKey(new X509Certificate2(builder.Configuration["Saml:IDPCertificateFileName"]));
options.IdentityProviders.Add(idp);
options.SPOptions.ServiceCertificates.Add(new X509Certificate2(builder.Configuration["Saml:SPCertificateFileName"]));
});
  • DefaultAuthenticateScheme需要设置为ApplicationSamlConstants.Application方案才能进行注销。控制器中的Authorize属性需要显式选择方案JwtBearerDefaults.AuthenticationScheme-请参阅下文
  • 需要设置Sustainsys.Saml2参数SingleLogoutServiceBindingSingleLogoutServiceUrlDisableOutboundLogoutRequests

SamlController.cs

[AllowAnonymous]
[HttpGet("InitiateSingleSignOn")]
public IActionResult InitiateSingleSignOn(string returnUrl)
{
// challenge the user to sign in using SAML
return new ChallengeResult(
Saml2Defaults.Scheme,
new AuthenticationProperties
{
RedirectUri = Url.Action(nameof(LoginCallback), new { returnUrl })
});
}
[AllowAnonymous]
[HttpGet("Callback")]
public async Task<IActionResult> LoginCallback(string returnUrl)
{
// authenticate and sign in
// (see https://stackoverflow.com/questions/53654020/how-to-implement-google-login-in-net-core-without-an-entityframework-provider for details)
var authenticateResult = await HttpContext.AuthenticateAsync(ApplicationSamlConstants.External);
if (!authenticateResult.Succeeded)
{
return Unauthorized();
}
var claimsIdentity = new ClaimsIdentity(ApplicationSamlConstants.Application);
claimsIdentity.AddClaim(authenticateResult.Principal.FindFirst(ClaimTypes.NameIdentifier));
claimsIdentity.AddClaim(authenticateResult.Principal.FindFirst("http://Sustainsys.se/Saml2/LogoutNameIdentifier"));
claimsIdentity.AddClaim(authenticateResult.Principal.FindFirst("http://Sustainsys.se/Saml2/SessionIndex"));
await HttpContext.SignInAsync(
ApplicationSamlConstants.Application,
new ClaimsPrincipal(claimsIdentity));

// issue JWT token
var token = this.CreateJwtSecurityToken(authenticateResult);
HttpContext.Session.SetString("JWT", new JwtSecurityTokenHandler().WriteToken(token));

// redirect to the page that caused our first challenge
if (!string.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
return this.Ok();
}

[AllowAnonymous]
[HttpGet("InitiateSingleLogout")]
public IActionResult InitiateSingleLogout(string returnUrl)
{
HttpContext.Session.SetString("JWT", "");
return SignOut(
new AuthenticationProperties()
{
RedirectUri = Url.Action(nameof(LogoutCallback), new { returnUrl })
},
ApplicationSamlConstants.External,
ApplicationSamlConstants.Application,
Saml2Defaults.Scheme
);
}
[AllowAnonymous]
[HttpGet("LogoutCallback")]
public IActionResult LogoutCallback(string returnUrl)
{
if (!string.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
return this.Ok();
}
  • LoginCallback中的SignInAsync逻辑对于注销的工作至关重要。ClaimPrincipal中需要包含这两项具体权利要求(请参见https://stackoverflow.com/a/59107708/5956120)。然后使用CCD_ 17方案在CCD_
  • 登录逻辑取自:如何在没有实体框架提供程序的情况下在.net核心中实现谷歌登录

AuthorizationController.cs

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[HttpGet("TestAuthorization")]
public ActionResult TestAuthorization()
{
return this.Ok("Congratulations, you are authorized.");
}
  • 为了使身份验证方案能够共存,在使用[Authorize]属性,则需要显式选择该方案。有关详细信息,请参阅:https://learn.microsoft.com/en-us/aspnet/core/security/authorization/limitingidentitybyscheme?view=aspnetcore-6.0

您正在使用什么作为服务提供商。

相关内容

  • 没有找到相关文章

最新更新