I found half an hour this morning to look at Waffle issue #8493.
Negotiate is a multi-step protocol. After an initial request the Waffle authentication provider will add an entry to a hashtable mapping the new connection IDs to a newly obtained security context. At a subsequent step, the security context is retrieved from the hashtable and used to continue the authentication protocol. If the connection is abandoned half way through this process, a handle will remain in the hashtable forever.
One of the solutions is to swap the hash structure for a cache that expires entries. I found Guava (aka Google-collections). Here’s my new concurrent hashmap with expiration.
ConcurrentMap<String, CtxtHandle> _continueContexts = new MapMaker()
.expiration(10, TimeUnit.SECONDS)
.makeMap();
It couldn’t have been easier.