Pregunta

Estoy modificando un sistema existente que utiliza SharePoint 2013 con la Autenticación Basada en Formularios (FBA) para permitir a los usuarios del servicio de auto-creación de cuentas y la gestión de las cuentas.Una de las cosas que se pueden administrar es el papel de los miembros;efectivamente, se les da una función de código de acceso que proporcionan al sistema, y se añade a la función, lo que les permite acceder a sitios que el papel se ha concedido acceso.Parte de la solución es una costumbre pantalla de inicio de sesión para ayudar a soportar todo esto y hacerlo más amigable para el usuario.Todo esto está funcionando relativamente bien.

La tarea que estoy trabajando en ello la adición de soporte para la autenticación externa de los proveedores en lugar de la autenticación basada en formularios - este es un requisito de negocio.Hay un montón de información en línea (e.g. http://blogs.msdn.com/b/mvpawardprogram/archive/2011/06/17/mvps-for-sharepoint-2010-using-azure-acs-v2-to-authenticate-external-systems-users.aspx) sobre cómo agregar Azure ACS como un proveedor de identidad y que está funcionando.Ahora, la cuestión es cómo agregar la auto-función de servicio de la autorización de la pieza.

Me he metido simple reclamaciones de aumento de trabajar muy bien siguiendo la guía en http://www.microsoft.com/en-us/download/details.aspx?id=27569.El problema que me estoy pegando es el "común" problema de la in-box PTS haciendo el almacenamiento en caché en el token, por lo que cuando un usuario de la función de pertenencia es cambiado, que los antiguos caché token todavía.Mis reclamos de aumento código no se llama (por supuesto que no - ¿por qué iba a ser cuando el PTS es el uso de una caché de entradas), así que el cambio en la membresía no está siendo visto.

Este es prácticamente el mismo tipo de problema que se tratan en compruebe los permisos de mostrar información incorrecta y http://www.shillier.com/archive/2010/10/25/authorization-failures-with-claims-based-authentication-in-sharepoint-2010.aspx, con la respuesta común de cambiar el token de vida dado.Tengo un par de temas y preguntas sobre este tema.

  1. En el exterior de las reclamaciones escenario, ¿cuál es la vida útil de aplicar?No es un token de Windows, y no es un FBA token, por lo que tampoco WindowsTokenLifetime ni FormsTokenLifetime parece adecuado, aunque esos son los dos todo el mundo dice que para cambiar.

  2. No quiero que el token a punto de expirar para el usuario final en un irrazonablemente corto tiempo, sólo quiero que el PTS para que caduque la versión en caché o idealmente nunca caché del todo (sé que hay un problema de rendimiento no - no me importa, para nuestra escala no importa).Parece que esas dos cosas están acoplados, aunque.Hay una manera de disociar ellos?

  3. Si no puedo separar, hay una forma de que la pantalla de inicio de sesión para indicar al sistema que quiero que el reclamo de volver a ser aumentada?Puedo yo mismo mediante la modificación de la identidad del usuario actual?Que va detrás de la posterior del sistema de curso, por lo que no quiero hacer que si me pueden ayudar a ello.

  4. Todo esto parece venir de abajo para el almacenamiento en caché en el OOB PTS ya que todas las otras partes en movimiento parecen estar en lo correcto.Es la manera "correcta" para evitar esto para crear una personalizada PTS que no tiene el comportamiento de la caché y registrarlo como un proveedor de identidad?(Si tengo una custom PTS parece que no me molestaría con los reclamos de aumento en ese momento, acababa de emitir todas las reclamaciones, en el primer lugar.) Eso me parece una cantidad sustancial de trabajo, aunque (aunque sé que hay muestras incluyendo http://archive.msdn.microsoft.com/SelfSTS), especialmente porque parece que he de tener para la conexión de la parte superior de la conexión de Azure ACS, a continuación, como parte del proceso, donde el OOB PTS hace que "mágicamente" con un par de líneas de PowerShell y un poco de esfuerzo.

  5. O, ¿debo abandonar los reclamos y simplemente cambiar el FBA lado?Que se siente como una manera horrible de ir, ya que ahora tengo que conectar todos los OpenID cosas en mi código de autenticación para FBA, y me estoy moviendo hacia atrás lejos de reclamaciones cuando sé que debería estar moviendo a los reclamos.

Un retraso de decir 60 minutos es simplemente no es aceptable cuando en la FBA modelo me puede hacer el cambio inmediatamente, forzando al usuario a iniciar sesión de nuevo, que se obtiene de la nueva función de pertenencia.

¿Fue útil?

Solución

OK, tengo este trabajo (yay!), pero el hombre, fue muy duro.

Básicamente, usted necesita para forzar el token de ser re-emitida desde el PTS, que obliga a los reclamos de aumento de código para que se ejecute de nuevo.En mi caso, los requerimientos de la empresa eran un poco más complicado que eso, porque necesitaba realmente sólo tiene uno de los reclamos es posible, pero eso es fuera del inmediato alcance de esta pregunta.

Esencialmente, me fui de el código mencionado en https://stackoverflow.com/questions/8070456/re-calculate-claims-for-sharepoint-2010-user-while-the-user-is-still-logged-in/8185646#8185646 .Una cosa que tenía que hacer era quitar la e.ReissueCookie desde que rompió completamente de autenticación para mí (el usuario se ha conectado a cabo por la acción).En mi caso, yo no quería hacerlo a través de una página especial, así que he usado un usuario de valor específico en la Aplicación de la colección que tengo claro de inmediato a cabo después de actuar en él.El código correspondiente en mi receptor de eventos que agrega y elimina el código en global.asax de la siguiente manera:

        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
        }

El ClaimSupport la asamblea tiene algunos misceláneos código compartido:

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]";
            }
        }
    }
}

Una cosa que es realmente importante aquí es que si usted está manipulando a los reclamos, ya que estoy aquí, y esperar que los que dice ser reconocido por SharePoint, usted necesita para que coincida con el emisor de la información que SharePoint se usa con un SPClaim, por lo que el "latido del corazón", afirman.En la mayoría de los casos no importa nada de eso - las reclamaciones aumentador va a hacer lo correcto -, pero aquí, necesito tener sólo uno de los posibles conjunto de reclamos, por lo que tuve que manipular directamente en este código, en lugar de en las reivindicaciones de aumento de código.

También sé que usted puede importar los espacios de nombres para global.asax pero me preocupa otro código de usuario o de las manipulaciones de ese archivo, así que hice los cambios tan independiente como sea posible.

Licenciado bajo: CC-BY-SA con atribución
scroll top