Domanda

Sto modificando un sistema esistente che utilizza SharePoint 2013 con autenticazione basata su moduli (FBA) per consentire agli utenti di creazione di account di account e gestione dei conti. Una delle cose che possono gestire è l'appartenenza al ruolo; In effetti, vengono forniti un codice di accesso al ruolo che fornisce al sistema e aggiunge loro il ruolo, consentendo loro di accedere ai siti che il ruolo è stato concesso l'accesso a. Parte della soluzione è una schermata di accesso personalizzata per supportare tutto questo e renderlo più facile da usare. Tutto ciò funziona relativamente bene.

L'attività che sto lavorando aggiungendo il supporto per i fornitori di autenticazione esterni piuttosto che l'autenticazione basata su moduli - questo è un requisito aziendale. C'è un sacco di informazioni online (ad es. http://blogs.msdn.com/b/mvpawardprogram/archive/2011/06/17/mvps-for-sharePoint-2010- Usando-Azure-ACS-V2-to-Authenticate-External-Systems-Users.aspx ) su come aggiungere Azure ACS come fornitore di identità e che funziona. Il problema è ora come aggiungere il pezzo di autorizzazione del ruolo self-service.

Ho ottenuto semplici rivendicazioni Auditionment che lavora bene seguendo la guida a http://www.microsoft.com/en-us/download/details.aspx?id=27569 . Il problema che sto colpendo è il problema "comune" della STS in-box che fa la cache sul token, quindi quando è cambiata l'abbonamento del ruolo di un utente, ottengono ancora il vecchio token memorizzato nella cache. Il codice di aumento dei miei reclami non è chiamato (ovviamente no - perché sarebbe quando le STS utilizzano un biglietto memorizzato nella cache), quindi il cambiamento nell'appartenenza non viene visto.

Questo è praticamente lo stesso tipo di problema discusso a Controlla le autorizzazioni che mostrano informazioni errate < / a> e http://www.shillier.com/archive/2010/10/25/authorization-failures-with-claims-based-authentication-in-sharePoint-2010.aspx , con la risposta comune di cambiare la durata del token data. Ho qualche problema con e domande su questo.

    .
  1. Nello scenario di rivendicazioni esterne, qual è la vita applicata? Non è un token di Windows, e non è un token FBA, quindi né WindowsTokenLifetimeFormsTokenLifetime sembrano appropriati, anche se quelli sono i due tutti dicono di cambiare.

  2. Non voglio che il token scada per l'utente finale in un tempo irragionevolmente breve, voglio solo che le ST scavidano la versione memorizzata nella cache o idealmente mai cache (so che c'è un problema di prestazione lì - Non mi interessa, per la nostra scala non importa). Sembra che quelle due cose siano accoppiate, però. C'è un modo per disaccoppiarli?

  3. Se non riesco a decouple, c'è un modo per la schermata di accesso per indicare al sistema che voglio che la pretesa sia ri-aumentata? Posso solo per me stesso modificando l'attuale identità dell'utente? Questo sta andando dietro il retro del sistema, quindi non voglio farlo se posso aiutarlo.

  4. Tutto ciò sembra infine arrivare alla cache nei STS OOB poiché tutte le altre parti mobili sembrano essere giuste. È il modo "giusto" per evitare questo per creare una STS personalizzata che non ha il comportamento nella cache e registrarlo come fornitore di identità? (Se ho una STS personalizzata, sembra che non mi preoccuperesse di Audition Aumenti a quel punto, emetterei tutte le rivendicazioni adeguate in primo luogo.) Sembra una notevole quantità di lavoro però (anche se lo so Ci sono campioni tra cui http://archive.msdn.microsoft.com/selfsts ), specialmente Dal momento che sembra che io abbia dovuto collegare il collegamento del partito di affidatore con Azure ACS allora come parte del processo, dove l'OOB STS fa quella "magicamente" con poche righe di PowerShell e qualche sforzo. .

  5. o, devo abbandonare le affermazioni e semplicemente cambiare il lato FBA? Ciò sembra un modo orribile da percorrere da quando ora ho bisogno di collegare tutte le cose openid nel mio codice di autenticazione per FBA, e mi sto muovendo indietro dalle rivendicazioni quando so che dovrei spostarsi in rivendicazioni.

    Un ritardo di dire che 60 minuti non è semplicemente accettabile quando nel modello FBA posso renderlo immediatamente la modifica forzando l'utente di accedere nuovamente, il che ottiene il nuovo abbonamento.

È stato utile?

Soluzione

Ok, ho avuto questo lavoro (yay!), Ma l'uomo, era difficile.

Fondamentalmente, è necessario forzare il token per essere ri-emesso dalla STS, che costringe il codice di aumento dei rivendicazioni di eseguire nuovamente. Nel mio caso, i requisiti aziendali erano un po 'più complicati di così, perché avevo bisogno di avere effettivamente possibile avere solo una delle rivendicazioni possibili, ma non è al di fuori dell'ambito immediato di questa domanda.

Essenzialmente, sono andato fuori dal codice menzionato a https://stackoverflow.com/questions/8070456/re-calculate-claims-for-sharePoint-2010-UR-HILE-HILE-HEUL -in / 8185646 # 8185646 . Una cosa che dovevo fare è stato rimuovere il e.ReissueCookie poiché ciò ha completamente rotto l'autenticazione per me (l'utente è stato disconnesso da quell'azione). Nel mio caso, non volevo farlo attraverso una pagina speciale, quindi ho usato un valore specifico per l'utente nella raccolta dell'applicazione che mi cancello immediatamente dopo aver agitato su di esso. Il codice pertinente nel mio ricevitore evento aggiunge e rimuove il codice in global.asax segue:

        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
        }
.

Il gruppo ClaimSupport contiene alcuni Codice condiviso Varie:

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 che è davvero importante qui è che se stai manipolare affermazioni, come sono qui, e ti aspetti che quelle affermazioni siano riconosciute da SharePoint, è necessario abbinare le informazioni dell'emittente che SharePoint utilizzerebbe con un SPCLAIM, che è Perché il "battito del cuore" afferma. Nella maggior parte dei casi non ti importa di nulla - le affermazioni Augmenter farà la cosa giusta - ma qui, ho bisogno di avere solo uno dei possibili serie di affermazioni, quindi ho dovuto manipolare direttamente in questo codice invece di il codice di aumento dei reclami.

So inoltre che puoi importare spazi dei nomi su global.asax ma sono preoccupato per altri codici o manipolazioni utente di quel file, quindi ho effettuato le modifiche nel modo più indipendente possibile.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a sharepoint.stackexchange
scroll top