2015-07-06 12 views
5

के साथ ऑनस्डिंग हेडर्स डेडलॉक को हल करना मैं कटाना प्रोजेक्ट द्वारा प्रदान किए गए ओपनआईडी कनेक्ट प्रमाणीकरण मिडलवेयर का उपयोग करने की कोशिश कर रहा हूं।कटाना ओपनआईडी कनेक्ट मिडलवेयर

वहाँ जो इन परिस्थितियों में एक गतिरोध का कारण बनता है कार्यान्वयन में एक बग है:

  1. एक मेजबान जहां अनुरोध धागे की आत्मीयता (जैसे आईआईएस) है में चल रहा है।
  2. ओपनआईडी कनेक्ट मेटाडाटा दस्तावेज़ पुनर्प्राप्त नहीं किया गया है या कैश की गई प्रति समाप्त हो गई है।
  3. एप्लिकेशन प्रमाणीकरण विधि के लिए SignOut पर कॉल करता है।
  4. एप्लिकेशन में एक क्रिया होती है जो प्रतिक्रिया स्ट्रीम को लिखने का कारण बनती है।

प्रमाणीकरण मिडलवेयर मेजबान सिग्नलिंग से कॉलबैक को संभालने के तरीके के कारण होता है जो हेडर भेजे जा रहे हैं।

private static void OnSendingHeaderCallback(object state) 
{ 
    AuthenticationHandler handler = (AuthenticationHandler)state; 
    handler.ApplyResponseAsync().Wait(); 
} 

से Microsoft.Owin.Security.Infrastructure.AuthenticationHandler

जब लौटे Task पहले से ही पूरा कर लिया है जो इसे OpenID Connect के मामले में नहीं किया है Task.Wait() करने के लिए कॉल केवल सुरक्षित है: समस्या के मूल इस विधि में है मिडलवेयर।

मिडलवेयर इसकी कॉन्फ़िगरेशन की कैश की गई प्रति प्रबंधित करने के लिए Microsoft.IdentityModel.Protocols.ConfigurationManager<T> का उदाहरण उपयोग करता है। यह SemaphoreSlim का उपयोग एसिंक्रोनस लॉक और कॉन्फ़िगरेशन प्राप्त करने के लिए HTTP दस्तावेज़ पुनर्प्राप्ति के रूप में एक असंगत कार्यान्वयन है। मुझे लगता है कि यह डेडलॉक Wait() कॉल का ट्रिगर होगा।

public async Task<T> GetConfigurationAsync(CancellationToken cancel) 
{ 
    DateTimeOffset now = DateTimeOffset.UtcNow; 
    if (_currentConfiguration != null && _syncAfter > now) 
    { 
     return _currentConfiguration; 
    } 

    await _refreshLock.WaitAsync(cancel); 
    try 
    { 
     Exception retrieveEx = null; 
     if (_syncAfter <= now) 
     { 
      try 
      { 
       // Don't use the individual CT here, this is a shared operation that shouldn't be affected by an individual's cancellation. 
       // The transport should have it's own timeouts, etc.. 

       _currentConfiguration = await _configRetriever.GetConfigurationAsync(_metadataAddress, _docRetriever, CancellationToken.None); 
       Contract.Assert(_currentConfiguration != null); 
       _lastRefresh = now; 
       _syncAfter = DateTimeUtil.Add(now.UtcDateTime, _automaticRefreshInterval); 
      } 
      catch (Exception ex) 
      { 
       retrieveEx = ex; 
       _syncAfter = DateTimeUtil.Add(now.UtcDateTime, _automaticRefreshInterval < _refreshInterval ? _automaticRefreshInterval : _refreshInterval); 
      } 
     } 

     if (_currentConfiguration == null) 
     { 
      throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10803, _metadataAddress ?? "null"), retrieveEx); 
     } 

     // Stale metadata is better than no metadata 
     return _currentConfiguration; 
    } 
    finally 
    { 
     _refreshLock.Release(); 
    } 
} 

मैं थ्रेड पूल पर निरंतरता मार्शल करने के प्रयास में बहुप्रतीक्षित कार्यों के सभी के लिए .ConfigureAwait(false) जोड़ने की कोशिश की है, न कि ASP.NET:

इस विधि मैं कारण हो पर शक है कार्यकर्ता धागा, लेकिन मुझे डेडलॉक से बचने में कोई सफलता नहीं मिली है।

क्या कोई गहरा मुद्दा है जिसका मैं सामना कर सकता हूं? मुझे घटकों को बदलने में कोई फर्क नहीं पड़ता - मैंने पहले ही IConfiguratioManager<T> के अपने प्रयोगात्मक कार्यान्वयन बनाए हैं। क्या कोई साधारण फिक्स है जिसे डेडलॉक को रोकने के लिए लागू किया जा सकता है?

+0

मुझे उम्मीद नहीं है कि यह कुछ भी बदलेगा, लेकिन 'प्रतीक्षा करें()' के बजाय GetAwaiter()। GetResult() 'को आजमाएं। –

+0

@PauloMorgado दुर्भाग्य से, 'ऑनसेंडिंग हैडर' कोड को 'प्रमाणीकरण हैंडलर' वर्ग में गहरा दफनाया गया है और इसे बदला नहीं जा सकता है। –

+0

वैकल्पिक रूप से, 'कार्य' IsComplete 'के लिए प्रतीक्षा करने का प्रयास करें। संदर्भ स्विच किए बिना प्रतीक्षा करने के लिए [स्पिनवाइट] (https://msdn.microsoft.com/library/system.threading.spinwait.aspx "स्पिनवाइट संरचना") का उपयोग करें। –

उत्तर

2

@ ट्रेगेडियन हमने इस मुद्दे के लिए इन सुधारों को लिया। क्या आप अपडेट कर सकते हैं और देख सकते हैं कि समस्या अभी भी मौजूद है (हमने सोचा कि हमने इसे 184 के साथ तय किया है, लेकिन जैसा कि आप देखते हैं कि हमारे पास 185 था)। एक और ग्राहक को नवीनतम नुजेट के साथ सफलता मिली है।

http://www.nuget.org/packages/Microsoft.IdentityModel.Protocol.Extensions/1.0.2.206221351

https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/185/files

https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/184/files

+0

मैं निश्चित रूप से फिर से परीक्षण और स्वीकार करूँगा। –

+0

@ ट्रेगेडियन ने यह काम आपके लिए किया था? –

+0

मुझे केवल संक्षेप में परीक्षण करने का अवसर मिला है। यह मेरा प्रारंभिक परीक्षण परिदृश्य पारित कर दिया, लेकिन मुझे यह सत्यापित करने के लिए और कुछ करने की आवश्यकता है कि मैं अब डेडलॉक नहीं बना सकता। जब मैं ठीक से फिक्स को सत्यापित करने का अवसर प्राप्त करता हूं तो मैं इस जवाब को स्वीकार करूंगा। –

1

मैं स्वीकार किए जाते हैं जवाब पर टिप्पणी नहीं कर सकता, लेकिन फिर भी है कि विशिष्ट nuget समस्या के साथ मेरे लिए जारी रहती है लगता है:/

मैं मैंने पाया है कि मुझे कॉन्फ़िगरेशन मैनेजर # GetConfigurationAsync लाइनों को संशोधित करने की आवश्यकता है:

await _refreshLock.WaitAsync(cancel); 

को

_refreshLock.Wait(cancel); 

और

_currentConfiguration = await _configRetriever.GetConfigurationAsync(_metadataAddress, _docRetriever, CancellationToken.None) 

को

_currentConfiguration = _configRetriever.GetConfigurationAsync(_metadataAddress, _docRetriever, CancellationToken.None).Result; 

या वैकल्पिक रूप से मैं कॉल के दोनों पर एक ConfigureAwait (गलत) रख दिया और दूसरे में 'GetConfigurationAsync' लपेट विधि जो 'Resesult' कॉल के साथ ब्लॉक करती है और उसे पहले से ही पूरा किए गए कार्य में लौटाती है।

मैं यह कर, तो लॉग आउट करने पर गतिरोध अब मेरे लिए 1 से अधिक उपयोगकर्ता (पिछले ठीक लॉग आउट एक एकल उपयोगकर्ता को संबोधित किया।)

हालांकि स्पष्ट रूप से इस 'GetConfigurationAsync' विधि निश्चित कर रहा है के लिए हो तुल्यकालिक:/

+1

आपके प्रस्तावित कोड परिवर्तनों के साथ मुझे अभी भी डेडलॉक मिला है। मैंने जो किया - वह बदल गया '_refreshLock.Wait (रद्द करें);' और '_configRetriever.GetConfigurationAsync (...)। "कॉन्फ़िगर करें (झूठी);'। यह मुझे डेडलॉक पाने के लिए रोक रहा है, हालांकि - यह सुनिश्चित नहीं है कि कोड सही है। –

संबंधित मुद्दे