عمر رمز STS للمطالبات الخارجية (على سبيل المثال.ز.أزور ACS)

sharepoint.stackexchange https://sharepoint.stackexchange.com//questions/75675

سؤال

أقوم بتعديل نظام موجود يستخدم SharePoint 2013 مع المصادقة المستندة إلى النماذج (FBA) للسماح للمستخدمين بإنشاء الخدمة الذاتية للحسابات وإدارة الحسابات.أحد الأشياء التي يمكنهم إدارتها هي عضوية الدور؛بشكل فعال، يتم منحهم رمز وصول للدور الذي يقدمونه للنظام، ويضيفهم إلى الدور، مما يسمح لهم بالوصول إلى المواقع التي تم منح الدور الوصول إليها.جزء من الحل هو شاشة تسجيل دخول مخصصة للمساعدة في دعم كل هذا وجعله أكثر سهولة في الاستخدام.كل هذا يعمل بشكل جيد نسبيا.

المهمة التي أعمل عليها هي إضافة دعم لموفري المصادقة الخارجيين بدلاً من المصادقة المستندة إلى النماذج - وهذا من متطلبات العمل.هناك الكثير من المعلومات عبر الإنترنت (على سبيل المثال.ز. http://blogs.msdn.com/b/mvpawardprogram/archive/2011/06/17/mvps-for-sharepoint-2010-using-azure-acs-v2-to-authenticate-external-systems-users.aspx) حول كيفية إضافة Azure ACS كموفر هوية وهذا يعمل.تكمن المشكلة الآن في كيفية إضافة قطعة ترخيص دور الخدمة الذاتية.

لقد حصلت على زيادة في المطالبات البسيطة تعمل بشكل جيد باتباع الدليل الموجود في http://www.microsoft.com/en-us/download/details.aspx?id=27569.المشكلة التي أواجهها هي المشكلة "الشائعة" المتمثلة في قيام STS الموجود في الصندوق بالتخزين المؤقت على الرمز المميز، لذلك عندما يتم تغيير عضوية دور المستخدم، فإنه لا يزال يحصل على الرمز المميز القديم المخزن مؤقتًا.لم يتم استدعاء رمز زيادة المطالبات الخاص بي (بالطبع لا - لماذا يتم ذلك عندما تستخدم STS تذكرة مخبأة)، لذلك لا يتم رؤية التغيير في العضوية.

هذا هو إلى حد كبير نفس النوع من القضايا التي تمت مناقشتها في تحقق من الأذونات التي تظهر معلومات غير صحيحة و http://www.shillier.com/archive/2010/10/25/authorization-failures-with-claims-based-authentication-in-sharepoint-2010.aspx, ، مع الإجابة الشائعة المتمثلة في تغيير عمر الرمز المميز.لدي بعض المشاكل والأسئلة حول هذا الموضوع.

  1. في سيناريو المطالبات الخارجية، ما هو العمر المطبق؟إنه ليس رمزًا مميزًا لنظام التشغيل Windows، وليس رمزًا مميزًا لـ FBA، وكذلك أيضًا WindowsTokenLifetime ولا FormsTokenLifetime يبدو مناسبًا، على الرغم من أن هذين هما الأمران اللذان يقول الجميع أنهما يجب تغييرهما.

  2. لا أريد أن تنتهي صلاحية الرمز المميز للمستخدم النهائي في وقت قصير بشكل غير معقول، أريد فقط أن تنتهي STS من النسخة المخزنة مؤقتًا أو من الأفضل عدم تخزينها مؤقتًا على الإطلاق (أعلم أن هناك مشكلة في الأداء هناك - لا أهتم ، بالنسبة لحجمنا لن يهم).ومع ذلك، يبدو أن هذين الأمرين مقترنان.هل هناك طريقة لفصلهم؟

  3. إذا لم أتمكن من الفصل، فهل هناك طريقة لتشير شاشة تسجيل الدخول للنظام إلى أنني أريد إعادة زيادة المطالبة؟هل يمكنني القيام بذلك بنفسي عن طريق تعديل هوية المستخدم الحالية؟هذا يحدث من وراء ظهر النظام بالطبع، لذا لا أريد أن أفعل ذلك إذا كان بإمكاني مساعدته.

  4. يبدو أن كل هذا يرجع في النهاية إلى التخزين المؤقت في OOB STS نظرًا لأن جميع الأجزاء المتحركة الأخرى تبدو صحيحة.هل الطريقة "الصحيحة" لتجنب ذلك هي إنشاء STS مخصص لا يحتوي على سلوك التخزين المؤقت وتسجيله كموفر هوية؟(إذا كان لدي STS مخصص، فيبدو أنني لن أهتم بزيادة المطالبات في تلك المرحلة، سأقوم فقط بإصدار جميع المطالبات المناسبة في المقام الأول.) يبدو أن هذا يتطلب قدرًا كبيرًا من العمل (على الرغم من أنني أعرف هناك عينات بما في ذلك http://archive.msdn.microsoft.com/SelfSTS) ، خاصة أنه يبدو أنه يتعين عليّ ربط اتصال الطرف المعتمد بـ Azure ACS ثم كجزء من العملية، حيث يقوم OOB STS بذلك "بطريقة سحرية" باستخدام بضعة أسطر من PowerShell وبعض الجهد.

  5. أم هل أحتاج إلى التخلي عن المطالبات وتغيير جانب FBA ببساطة؟تبدو هذه طريقة مروعة لأنني الآن بحاجة إلى ربط جميع عناصر OpenID في رمز المصادقة الخاص بي لـ FBA، وأنا أتحرك للخلف بعيدًا عن المطالبات عندما أعلم أنني يجب أن أنتقل إلى المطالبات.

إن التأخير لمدة 60 دقيقة على سبيل المثال أمر غير مقبول ببساطة عندما يمكنني في نموذج FBA إجراء التغيير على الفور عن طريق إجبار المستخدم على تسجيل الدخول مرة أخرى، مما يحصل على عضوية الدور الجديد.

هل كانت مفيدة؟

المحلول

حسنًا، لقد نجح هذا الأمر (رائع!)، لكن يا رجل، كان الأمر صعبًا.

في الأساس، تحتاج إلى فرض إعادة إصدار الرمز المميز من STS، مما يفرض تشغيل رمز زيادة المطالبات مرة أخرى.في حالتي، كانت متطلبات العمل أكثر تعقيدًا من ذلك بقليل، لأنني كنت بحاجة إلى الحصول على مطالبة واحدة فقط ممكنة، ولكن هذا خارج النطاق المباشر لهذا السؤال.

في الأساس، لقد خرجت عن الكود المذكور في https://stackoverflow.com/questions/8070456/re-calculate-claims-for-sharepoint-2010-user-while-the-user-is-still-logged-in/8185646#8185646 .شيء واحد كان علي فعله هو إزالة e.ReissueCookie منذ أن أدى ذلك إلى كسر المصادقة تمامًا بالنسبة لي (تم تسجيل خروج المستخدم من خلال هذا الإجراء).في حالتي، لم أرغب في القيام بذلك من خلال صفحة خاصة، لذلك استخدمت قيمة خاصة بالمستخدم في مجموعة التطبيقات التي قمت بإزالتها فورًا بعد التصرف بناءً عليها.الكود ذو الصلة في جهاز استقبال الأحداث الخاص بي الذي يضيف ويزيل الكود الموجود global.asax يتبع:

        private readonly string AsaxText = @"
<%@ Assembly Name=""" + System.Reflection.Assembly.GetAssembly(typeof(ClaimSupport)).FullName + @"""%>
<script runat='server'> 
    void SessionAuthentication_SessionSecurityTokenReceived(object sender, Microsoft.IdentityModel.Web.SessionSecurityTokenReceivedEventArgs e) { 
        var application = HttpContext.Current.Application;
        if (application == null) {
            return;
        }
        var key = Company.SharePoint.Authentication.Data.ClaimSupport.ApplicationEventKey(e.SessionToken.ClaimsPrincipal.Identity.Name);
        var applicationValue = application[key];
        if (applicationValue == null) { 
            return;
        }
        var applicationString = applicationValue.ToString();
        if (string.IsNullOrWhiteSpace(applicationString)) {
            return;
        }
        application[key] = null;
        var sam = sender as Microsoft.IdentityModel.Web.SessionAuthenticationModule; 
        var logonWindow = Microsoft.SharePoint.Administration.Claims.SPSecurityTokenServiceManager.Local.LogonTokenCacheExpirationWindow; 
        var newValidTo = System.DateTime.UtcNow.Add(logonWindow);
        var currentPrincipal = e.SessionToken.ClaimsPrincipal;
        var claimsIdentity = (Microsoft.IdentityModel.Claims.IClaimsIdentity)currentPrincipal.Identity;

        var heartbeatClaim = GetHeartbeatClaim(claimsIdentity);
        var issuer = heartbeatClaim.Issuer;
        var originalIssuer = heartbeatClaim.OriginalIssuer;
        RemoveExistingEventClaims(claimsIdentity);
        AddEventClaim(claimsIdentity, applicationString, issuer, originalIssuer);

        e.SessionToken = sam.CreateSessionSecurityToken( 
            currentPrincipal, 
            e.SessionToken.Context, 
            e.SessionToken.ValidFrom, 
            newValidTo, 
            e.SessionToken.IsPersistent); 
        //e.ReissueCookie = true; - commented out because it broke things for me, but kept for reference
    } 

    private Microsoft.IdentityModel.Claims.Claim GetHeartbeatClaim(Microsoft.IdentityModel.Claims.IClaimsIdentity claimsIdentity) {
        var heartbeatClaim = (from c in claimsIdentity.Claims
                              where
                                  (c.ClaimType == Company.SharePoint.Authentication.Data.ClaimSupport.EventClaimType)
                              &&
                                  (c.Value == Company.SharePoint.Authentication.Data.ClaimSupport.HeartbeatClaimValue)
                              select c).FirstOrDefault();
        return heartbeatClaim;
    }

    private void AddEventClaim(Microsoft.IdentityModel.Claims.IClaimsIdentity claimsIdentity, string additionalEvent, string issuer, string originalIssuer) {
        var eventClaim = new Microsoft.IdentityModel.Claims.Claim(Company.SharePoint.Authentication.Data.ClaimSupport.EventClaimType, additionalEvent, HynesITe.SharePoint.Authentication.Data.ClaimSupport.EventClaimValueType, issuer, originalIssuer);
        claimsIdentity.Claims.Add(eventClaim);
    }

    private static void RemoveExistingEventClaims(Microsoft.IdentityModel.Claims.IClaimsIdentity claimsIdentity) {
        var currentClaims = (from c in claimsIdentity.Claims
                             where
                                 (c.ClaimType == HynesITe.SharePoint.Authentication.Data.ClaimSupport.EventClaimType)
                             &&
                                 (c.Value != HynesITe.SharePoint.Authentication.Data.ClaimSupport.HeartbeatClaimValue)
                             select c).ToList();
        foreach (var claim in currentClaims) {
            claimsIdentity.Claims.Remove(claim);
        }
    }
</script> 
";

        private void AddGlobalAsax(SPFeatureReceiverProperties properties) {
            var webApp = properties.Feature.Parent as SPWebApplication;
            if (webApp == null) {
                throw new SPException("Cannot add global.asax entries.");
            }
            var zones = Enum.GetValues(typeof(SPUrlZone)).Cast<SPUrlZone>().ToArray();
            var paths =
                zones.Select(z => Path.Combine(webApp.GetIisSettingsWithFallback(z).Path.ToString(), "global.asax"))
                    .Distinct().Where(File.Exists).ToArray();
            var globalAsaxFiles = new List<string>();
            globalAsaxFiles.AddRange(paths);
            foreach (var asax in from asax in globalAsaxFiles
                                 let contents = File.ReadAllText(asax)
                                 where !contents.Contains(AsaxText)
                                 select asax) {
                File.AppendAllText(asax, AsaxText);
            }
        }

        private void RemoveGlobalAsax(SPFeatureReceiverProperties properties) {
            var webApp = properties.Feature.Parent as SPWebApplication;
            if (webApp == null) {
                throw new SPException("Cannot add global.asax entries.");
            }
            var zones = Enum.GetValues(typeof(SPUrlZone)).Cast<SPUrlZone>().ToArray();
            var paths =
                zones.Select(z => Path.Combine(webApp.GetIisSettingsWithFallback(z).Path.ToString(), "global.asax"))
                    .Distinct().Where(File.Exists).ToArray();
            var globalAsaxFiles = new List<string>();
            globalAsaxFiles.AddRange(paths);
            foreach (var asax in globalAsaxFiles) {
                var contents = File.ReadAllText(asax);
                if (contents.Contains(AsaxText)) {
                    var replaced = contents.Replace(AsaxText, string.Empty);
                    File.WriteAllText(asax, replaced);
                }
            }
        }

        public override void FeatureActivated(SPFeatureReceiverProperties properties) {
            // other stuff
            AddGlobalAsax(properties);
            // other stuff
        }

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties) {
            // other stuff
            RemoveGlobalAsax(properties);
            // other stuff
        }

ال ClaimSupport يحتوي التجميع على بعض التعليمات البرمجية المشتركة المتنوعة:

namespace HynesITe.SharePoint.Authentication.Data {
    public static class ClaimSupport {
        public static string EventClaimType {
            get {
                return "http://schema.Company.com/events";
            }
        }

        public static string EventClaimValueType {
            get {
                return Microsoft.IdentityModel.Claims.ClaimValueTypes.String;
            }
        }

        public static string ApplicationEventKey(string username) {
            return username + ":CurrentEvent";
        }

        public static string ApplicationIssuerKey(string username) {
            return username + ":Issuer";
        }

        public static string ApplicationOriginalIssuerKey(string username) {
            return username + ":OriginalIssuer";
        }

        public static string HeartbeatClaimValue {
            get {
                return "[heartbeat]";
            }
        }
    }
}

هناك شيء واحد مهم حقًا هنا وهو أنه إذا كنت تتلاعب بالمطالبات، كما أنا هنا، وتتوقع أن يتم التعرف على هذه المطالبات بواسطة SharePoint، فستحتاج إلى مطابقة معلومات المُصدر التي سيستخدمها SharePoint مع مطالبة SPC، وهذا هو سبب " مطالبة نبض القلب.في معظم الحالات، لن تهتم بأي من ذلك - ستفعل أداة زيادة المطالبات الشيء الصحيح - ولكن هنا، أحتاج إلى الحصول على واحدة فقط من مجموعة المطالبات المحتملة، لذلك اضطررت إلى التعامل مباشرة في هذا الرمز بدلاً من ذلك رمز زيادة المطالبات.

أعلم أيضًا أنه يمكنك استيراد مساحات الأسماء إلى global.asax لكنني أشعر بالقلق بشأن التعليمات البرمجية الأخرى أو تلاعبات المستخدم بهذا الملف، لذا قمت بإجراء التغييرات بشكل مستقل قدر الإمكان.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى sharepoint.stackexchange
scroll top