我正在将我们的asp.net MVC应用程序与SAML2身份验证集成。并使用Kentor.AuthServices作为模块,如kentor.AuthServices Configuration
所述Everithing工作正常。但下一步是仅为指定的页面范围添加第二服务提供程序(配置为在服务器端使用其他身份验证机制)的使用。
首先,如何通过web.config配置它以使用不同的 entityId 添加第二个SP(不是第一个SP范围内的第二个IdP)。
第二,如何以编程方式切换到第二个SP?我认为它应该发生在方法 Application_BeginRequest 中的 global.asax 文件中,但是如何?
答案 0 :(得分:0)
在同一个应用程序中使用两个不同的SP实例是一种非常罕见的情况。但如果你确实需要它,那就可以实现。
您必须使用Kentor.AuthServices.Owin包并在代码中进行配置 - web.config不会这样做。注册两个中间件实例。每个人都有自己的配置,包括他们自己的SP EntityID。还要确保更改其中至少一个的ModulePath
,以便它们获得不同的端点地址。
要挑战任何一个身份验证,请在质询中设置正确的身份验证方案(通常在控制器返回的ChallengeResult
中)
答案 1 :(得分:0)
<强>自应答强>
这是针对MVC或HttpModule包的多个SP的解决方法,切换基于指定的URL范围。在我的情况下,不同的SP实现了不同数量的安全因素。
首先,实现自定义IOptions和CookieHandler,能够切换到正确的实例。在web.config文件中,必须定义两个kentor.authServices部分。在我的情况下,只有“entityId”属性不同。
public class CustomOptions : IOptions
{
private IOptions options1Factor;
private IOptions options2Factor;
private Func<bool> _checkIsSecure;
public CustomOptions(Func<bool> checkIsSecure)
{
_checkIsSecure = checkIsSecure;
AddOption(out options2Factor, "kentor.authServices1");
AddOption(out options1Factor, "kentor.authServices");
}
private void AddOption(out IOptions options, string sectionName)
{
var sp = new SPOptions((KentorAuthServicesSection)ConfigurationManager.GetSection(sectionName));
options = new Options(sp);
KentorAuthServicesSection.Current.IdentityProviders.RegisterIdentityProviders(options);
KentorAuthServicesSection.Current.Federations.RegisterFederations(options);
}
public SPOptions SPOptions
{
get
{
if (_checkIsSecure())
return options2Factor.SPOptions;
return options1Factor.SPOptions;
}
}
public IdentityProviderDictionary IdentityProviders
{
get
{
if (_checkIsSecure())
return options2Factor.IdentityProviders;
return options1Factor.IdentityProviders;
}
}
public KentorAuthServicesNotifications Notifications
{
get
{
if (_checkIsSecure())
return options2Factor.Notifications;
return options1Factor.Notifications;
}
}
}
public class CustomCookieHandler : CookieHandler
{
private Func<bool> _checkIsSecure;
private CookieHandler _originalCookieHandler1Factor;
private CookieHandler _originalCookieHandler2Factor;
public CustomCookieHandler(Func<bool> checkIsSecure)
{
_checkIsSecure = checkIsSecure;
_originalCookieHandler1Factor = new ChunkedCookieHandler()
{
Name = "commonAuth",
RequireSsl = false
};
_originalCookieHandler2Factor = new ChunkedCookieHandler()
{
Name = "securedAuth",
RequireSsl = false
};
}
public override string MatchCookiePath(Uri baseUri, Uri targetUri)
{
if (_checkIsSecure())
return _originalCookieHandler2Factor.MatchCookiePath(baseUri, targetUri);
return _originalCookieHandler1Factor.MatchCookiePath(baseUri, targetUri);
}
protected override void DeleteCore(string name, string path, string domain, HttpContext context)
{
if (_checkIsSecure())
_originalCookieHandler2Factor.Delete();
else
_originalCookieHandler1Factor.Delete();
}
protected override byte[] ReadCore(string name, HttpContext context)
{
if (_checkIsSecure())
return _originalCookieHandler2Factor.Read();
return _originalCookieHandler1Factor.Read();
}
protected override void WriteCore(byte[] value, string name, string path, string domain, DateTime expirationTime, bool secure, bool httpOnly, HttpContext context)
{
if (_checkIsSecure())
_originalCookieHandler2Factor.Write(value, true, expirationTime);
else
_originalCookieHandler1Factor.Write(value, true, expirationTime);
}
}
在Global.asax文件中将静态属性设置为自定义实现。无需进行更多修改。
protected void Application_Start()
{
FederatedAuthentication.FederationConfiguration.CookieHandler = new CustomCookieHandler(CheckIsSecure);
Kentor.AuthServices.Mvc.AuthServicesController.Options = new CustomOptions(CheckIsSecure);
}
private bool CheckIsSecure()
{
if (HttpContext.Current == null)
return false;
var mainHost = "http://host.local"; // host url
var sp = new [] { "/Home/Secure" }; // array of URLs which must be secured with other SP
var request = HttpContext.Current.Request;
var isSecured = sp.Any(x => x.Equals(request.Path, StringComparison.InvariantCultureIgnoreCase));
if (!isSecured && request.Path.Equals("/AuthServices/SignIn", StringComparison.InvariantCultureIgnoreCase))
{
var returnUrl = request.QueryString["ReturnUrl"];
isSecured = !string.IsNullOrEmpty(returnUrl) &&
sp.Any(x => x.Equals(returnUrl, StringComparison.InvariantCultureIgnoreCase));
}
if (!isSecured && request.Path.Equals("/AuthServices/Acs", StringComparison.InvariantCultureIgnoreCase))
{
var _r = new HttpRequestWrapper(request).ToHttpRequestData();
isSecured = _r != null && _r.StoredRequestState != null && _r.StoredRequestState.ReturnUrl != null
&& sp.Any(x => x.Equals(_r.StoredRequestState.ReturnUrl.ToString(),
StringComparison.InvariantCultureIgnoreCase));
}
if (!isSecured && !string.IsNullOrEmpty(request.Headers["Referer"]))
{
var referer = request.Headers["Referer"];
isSecured = sp
.Select(x => string.Format("{0}/{1}", mainHost.TrimEnd('/'), x.TrimStart('/')))
.Any(x => x.Equals(referer, StringComparison.InvariantCultureIgnoreCase));
}
return isSecured;
}