Hello,

I'm the author of open source claims provider LDAPCP (http://ldapcp.codeplex.com/) and I recently discovered a very important design constraint that causes serious issues if ignored:
Claims providers are mostly called by static class SPClaimProviderOperations (actually I think it's the only class that can call them).
This class and its methods are static, which implies that every thread will share the same instance of the claims provider class.
As a consequence, the claims provider itself must absolutely be thread safe, and its critical variables (the ones that store results) must be unique to the current thread, otherwise a thread may alter the result of another thread, and a user might get permissions/claims of another user.

To ensure thread safety, you need locks.
Regarding uniqueness of variables, since 1 instance of the claims provider is shared with multiple threads, variables of the class are also shared (they are allocated in the managed heap).
To illustrate this point, I created this small console application that simulates how SPClaimProviderOperations calls custom claims providers:

using System;
using System.Collections.ObjectModel;
using System.Threading;

namespace LDAPCP_2013_Console
{
public static class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
Thread oThread = new Thread(new ThreadStart(FakeSPClaimProviderOperations.CallFillResolve));
oThread.Start();
}
Console.ReadLine();
}
}

public static class FakeSPClaimProviderOperations
{
static FakeCustomClaimProvider cp;
public static void CallFillResolve()
{
if (cp == null) cp = new FakeCustomClaimProvider();
cp.FillResolve();
}
}

public class FakeCustomClaimProvider
{
// Collection shared by every thread
Collection<String> MyCollectionClass = new Collection<string>();

public void FillResolve()
{
// Collection unique to current thread
Collection<String> MyCollectionMethod = new Collection<string>();

MyCollectionMethod.Add("item1");
MyCollectionClass.Add("item1");

Console.WriteLine(String.Format("MyCollectionMethod has {0} items.", MyCollectionMethod.Count.ToString()));
Console.WriteLine(String.Format("MyCollectionClass has {0} items.\r\n", MyCollectionClass.Count.ToString()));
}
}
}

Output:
MyCollectionMethod has 1 items.
MyCollectionClass has 1 items.

MyCollectionMethod has 1 items.
MyCollectionClass has 2 items.

MyCollectionMethod has 1 items.
MyCollectionClass has 3 items.

MyCollectionMethod has 1 items.
MyCollectionClass has 4 items.

MyCollectionMethod has 1 items.
MyCollectionClass has 5 items.

To conclude, ensuring thread safety and isolation of variables is absolutely essential in custom claims providers, otherwise random permissions issues may occur and they are very difficult to track down.