Kentor Auth Services根据页面url选择programmaticaly entityId

时间:2017-09-20 09:29:58

标签: asp.net asp.net-mvc authentication kentor-authservices

我正在将我们的asp.net MVC应用程序与SAML2身份验证集成。并使用Kentor.AuthServices作为模块,如kentor.AuthServices Configuration

所述

Everithing工作正常。但下一步是仅为指定的页面范围添加第二服务提供程序(配置为在服务器端使用其他身份验证机制)的使用。

首先,如何通过web.config配置它以使用不同的 entityId 添加第二个SP(不是第一个SP范围内的第二个IdP)。

第二,如何以编程方式切换到第二个SP?我认为它应该发生在方法 Application_BeginRequest 中的 global.asax 文件中,但是如何?

2 个答案:

答案 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;
    }