English 中文(简体)
页: 1
原标题:Azure/web-farm ready SecurityTokenCache

Our site uses ADFS for auth. To reduce the cookie payload on every request we re turning IsSessionMode on (see Your fedauth cookies on a diet).

The last thing we need to do to get this working in our load balanced environment is to implement a farm ready SecurityTokenCache. The implementation seems pretty straightforward, I m mainly interested in finding out if there are any gotchas we should consider when dealing with SecurityTokenCacheKey and the TryGetAllEntries and TryRemoveAllEntries methods (SecurityTokenCacheKey has a custom implementation of the Equals and GetHashCode methods).

是否有这方面的实例? 我们重新规划使用“应用Fabric”作为后继储存,但使用任何持久性储存的范例将是有用的数据库表、“存储”等。

这里是我搜查的一些地方:

  • In Hervey Wilson s PDC09 session he uses a DatabaseSecurityTokenCache. I haven t been able to find the sample code for his session.
  • On page 192 of Vittorio Bertocci s excellent book, "Programming Windows Identity Foundation" he mentions uploading a sample implementation of an Azure ready SecurityTokenCache to the book s website. I haven t been able to find this sample either.

感谢!

jd

3/16/2012 UPDATE Vittorio s blog links to a sample using the new .net 4.5 stuff:

ClaimsAwareWebFarm This sample is an answer to the feedback we got from many of you guys: you wanted a sample showing a farm ready session cache (as opposed to a tokenreplycache) so that you can use sessions by reference instead of exchanging big cookies; and you asked for an easier way of securing cookies in a farm.

最佳回答

为了着手执行工作,我们最终不得不使用反射器分析Microsoft与会议相关的课堂。 身份模型。 下面是我们的。 安装在我们的牛楼和卡片环境中,似乎在工作上很出色,因此转而使用集回收机等。

In global.asax:

protected void Application_Start(object sender, EventArgs e)
{
    FederatedAuthentication.ServiceConfigurationCreated += this.OnServiceConfigurationCreated;
}

private void OnServiceConfigurationCreated(object sender, ServiceConfigurationCreatedEventArgs e)
{
    var sessionTransforms = new List<CookieTransform>(new CookieTransform[]
            {
                new DeflateCookieTransform(),
                new RsaEncryptionCookieTransform(
                    e.ServiceConfiguration.ServiceCertificate),
                new RsaSignatureCookieTransform(
                    e.ServiceConfiguration.ServiceCertificate)
            });

    // following line is pseudo code.  use your own durable cache implementation.
    var durableCache = new AppFabricCacheWrapper();

    var tokenCache = new DurableSecurityTokenCache(durableCache, 5000);
    var sessionHandler = new SessionSecurityTokenHandler(sessionTransforms.AsReadOnly(),
        tokenCache,
        TimeSpan.FromDays(1));

    e.ServiceConfiguration.SecurityTokenHandlers.AddOrReplace(sessionHandler);
}

private void WSFederationAuthenticationModule_SecurityTokenValidated(object sender, SecurityTokenValidatedEventArgs e)
{
    FederatedAuthentication.SessionAuthenticationModule.IsSessionMode = true;
}

Durable Security TokenCache.cs:

/// <summary>
/// Two level durable security token cache (level 1: in memory MRU, level 2: out of process cache).
/// </summary>
public class DurableSecurityTokenCache : SecurityTokenCache
{
    private ICache<string, byte[]> durableCache;
    private readonly MruCache<SecurityTokenCacheKey, SecurityToken> mruCache;

    /// <summary>
    /// The constructor.
    /// </summary>
    /// <param name="durableCache">The durable second level cache (should be out of process ie sql server, azure table, app fabric, etc).</param>
    /// <param name="mruCapacity">Capacity of the internal first level cache (in-memory MRU cache).</param>
    public DurableSecurityTokenCache(ICache<string, byte[]> durableCache, int mruCapacity)
    {
        this.durableCache = durableCache;
        this.mruCache = new MruCache<SecurityTokenCacheKey, SecurityToken>(mruCapacity, mruCapacity / 4);
    }

    public override bool TryAddEntry(object key, SecurityToken value)
    {
        var cacheKey = (SecurityTokenCacheKey)key;

        // add the entry to the mru cache.
        this.mruCache.Add(cacheKey, value);

        // add the entry to the durable cache.
        var keyString = GetKeyString(cacheKey);
        var buffer = this.GetSerializer().Serialize((SessionSecurityToken)value);
        this.durableCache.Add(keyString, buffer);

        return true;
    }

    public override bool TryGetEntry(object key, out SecurityToken value)
    {
        var cacheKey = (SecurityTokenCacheKey)key;

        // attempt to retrieve the entry from the mru cache.
        value = this.mruCache.Get(cacheKey);
        if (value != null)
            return true;

        // entry wasn t in the mru cache, retrieve it from the app fabric cache.
        var keyString = GetKeyString(cacheKey);

        var buffer = this.durableCache.Get(keyString);
        var result = buffer != null;
        if (result)
        {
            // we had a cache miss in the mru cache but found the item in the durable cache...

            // deserialize the value retrieved from the durable cache.
            value = this.GetSerializer().Deserialize(buffer);

            // push this item into the mru cache.
            this.mruCache.Add(cacheKey, value);
        }

        return result;
    }

    public override bool TryRemoveEntry(object key)
    {
        var cacheKey = (SecurityTokenCacheKey)key;

        // remove the entry from the mru cache.
        this.mruCache.Remove(cacheKey);

        // remove the entry from the durable cache.
        var keyString = GetKeyString(cacheKey);
        this.durableCache.Remove(keyString);

        return true;
    }

    public override bool TryReplaceEntry(object key, SecurityToken newValue)
    {
        var cacheKey = (SecurityTokenCacheKey)key;

        // remove the entry in the mru cache.
        this.mruCache.Remove(cacheKey);

        // remove the entry in the durable cache.
        var keyString = GetKeyString(cacheKey);

        // add the new value.
        return this.TryAddEntry(key, newValue);
    }

    public override bool TryGetAllEntries(object key, out IList<SecurityToken> tokens)
    {
        // not implemented... haven t been able to find how/when this method is used.
        tokens = new List<SecurityToken>();
        return true;
        //throw new NotImplementedException();
    }

    public override bool TryRemoveAllEntries(object key)
    {
        // not implemented... haven t been able to find how/when this method is used.
        return true;
        //throw new NotImplementedException();
    }

    public override void ClearEntries()
    {
        // not implemented... haven t been able to find how/when this method is used.
        //throw new NotImplementedException();
    }

    /// <summary>
    /// Gets the string representation of the specified SecurityTokenCacheKey.
    /// </summary>
    private string GetKeyString(SecurityTokenCacheKey key)
    {
        return string.Format("{0}; {1}; {2}", key.ContextId, key.KeyGeneration, key.EndpointId);
    }

    /// <summary>
    /// Gets a new instance of the token serializer.
    /// </summary>
    private SessionSecurityTokenCookieSerializer GetSerializer()
    {
        return new SessionSecurityTokenCookieSerializer();  // may need to do something about handling bootstrap tokens.
    }
}

MruCache.cs:

/// <summary>
/// Most recently used (MRU) cache.
/// </summary>
/// <typeparam name="TKey">The key type.</typeparam>
/// <typeparam name="TValue">The value type.</typeparam>
public class MruCache<TKey, TValue> : ICache<TKey, TValue>
{
    private Dictionary<TKey, TValue> mruCache;
    private LinkedList<TKey> mruList;
    private object syncRoot;
    private int capacity;
    private int sizeAfterPurge;

    /// <summary>
    /// The constructor.
    /// </summary>
    /// <param name="capacity">The capacity.</param>
    /// <param name="sizeAfterPurge">Size to make the cache after purging because it s reached capacity.</param>
    public MruCache(int capacity, int sizeAfterPurge)
    {
        this.mruList = new LinkedList<TKey>();
        this.mruCache = new Dictionary<TKey, TValue>(capacity);
        this.capacity = capacity;
        this.sizeAfterPurge = sizeAfterPurge;
        this.syncRoot = new object();
    }

    /// <summary>
    /// Adds an item if it doesn t already exist.
    /// </summary>
    public void Add(TKey key, TValue value)
    {
        lock (this.syncRoot)
        {
            if (mruCache.ContainsKey(key))
                return;

            if (mruCache.Count + 1 >= this.capacity)
            {
                while (mruCache.Count > this.sizeAfterPurge)
                {
                    var lru = mruList.Last.Value;
                    mruCache.Remove(lru);
                    mruList.RemoveLast();
                }
            }
            mruCache.Add(key, value);
            mruList.AddFirst(key);
        }
    }

    /// <summary>
    /// Removes an item if it exists.
    /// </summary>
    public void Remove(TKey key)
    {
        lock (this.syncRoot)
        {
            if (!mruCache.ContainsKey(key))
                return;

            mruCache.Remove(key);
            mruList.Remove(key);
        }
    }

    /// <summary>
    /// Gets an item.  If a matching item doesn t exist null is returned.
    /// </summary>
    public TValue Get(TKey key)
    {
        lock (this.syncRoot)
        {
            if (!mruCache.ContainsKey(key))
                return default(TValue);

            mruList.Remove(key);
            mruList.AddFirst(key);
            return mruCache[key];
        }
    }

    /// <summary>
    /// Gets whether a key is contained in the cache.
    /// </summary>
    public bool ContainsKey(TKey key)
    {
        lock (this.syncRoot)
            return mruCache.ContainsKey(key);
    }
}

Iache.cs:

/// <summary>
/// A cache.
/// </summary>
/// <typeparam name="TKey">The key type.</typeparam>
/// <typeparam name="TValue">The value type.</typeparam>
public interface ICache<TKey, TValue>
{
    void Add(TKey key, TValue value);
    void Remove(TKey key);
    TValue Get(TKey key);
}
问题回答

这是我所写的样本。 我将“Windows”储存成形,击败任何可能的再作用。

http://tokenreplaycache.codeplex.com/releases/view/76652”rel=“nofollow”> http://tokenreplaycache.codeplex.com/releases/view/76652

You will need to place this in your web.config:

    <service>
      <securityTokenHandlers>
        <securityTokenHandlerConfiguration saveBootstrapTokens="true">
          <tokenReplayDetection enabled="true" expirationPeriod="50" purgeInterval="1">
            <replayCache type="LC.Security.AzureTokenReplayCache.ACSTokenReplayCache,LC.Security.AzureTokenReplayCache, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          </tokenReplayDetection>
        </securityTokenHandlerConfiguration>
      </securityTokenHandlers>
    </service>




相关问题
Multiple webservice calls

I have a webservice (ASP.NET) deployed on a webfarm. A client application consumes it on daily basis. The problem is that some of its calls are duplicated (with difference of milliseconds). For ...

How to create an ASP.NET web farm?

I am looking for information on how to create an ASP.NET web farm - that is, how to make an ASP.NET application (initially designed to work on a single web server) work on 2, 3, 10, etc. servers? We ...

.net cache and its limitation in case of web farms?

hey. friends i dont know this question is really asked before or not ? but i need to know about .net cache and its limitation in case of web farms and not in case of web farms.. ?

热门标签