2015-11-04 5 views
6

मेरे पास एक साधारण HTTP सर्वर है जो ग्राहकों को नेगोशिएट प्रोटोकॉल के साथ प्रमाणित करता है। यह सर्वर प्रमाण-पत्र प्राप्त करने और सुरक्षा संदर्भ स्थापित करने के लिए एसएसपीआई कॉल का उपयोग करता है। सर्वर डोमेन में है और डोमेन उपयोगकर्ता की तरफ से चल रहा है। सब ठीक काम करता है और अगर मैं कंसोल मोड में सर्वर शुरू करता हूं तो मुझे HTTP 200 प्रतिक्रिया मिल रही है। हालांकि जब मैं इसे एक सेवा के रूप में चला रहा हूं तो मुझे SEC_E_INVALID_HANDLE त्रुटि मिल रही है। यहाँ क्या होता है जब मैं कंसोल मोड में शुरू होता है:AcceptSecurityContext विफल रहता है जब अनुप्रयोग सेवा के रूप में चल रहा है

1.Client भेजता HTTP GET अनुरोध http://localhost:8082

2.Server WWW-प्रमाणित के साथ प्रतिक्रिया: हेडर निगोशिएट।

3.Client प्राधिकरण हैडर भेजता है और निम्न डेटा में शामिल हैं:

60 73 06 06 2B 06 01 05 05 02 A0 69 30 67 A0 30 `s..+..... i0g 0 
30 2E 06 0A 2B 06 01 04 01 82 37 02 02 0A 06 09 0...+....7..... 
2A 86 48 82 F7 12 01 02 02 06 09 2A 86 48 86 F7 *H÷......*H÷ 
12 01 02 02 06 0A 2B 06 01 04 01 82 37 02 02 1E ......+....7... 
A2 33 04 31 4E 54 4C 4D 53 53 50 00 01 00 00 00 ¢3.1NTLMSSP..... 
97 B2 08 E2 04 00 04 00 2D 00 00 00 05 00 05 00 ².â....-....... 
28 00 00 00 06 01 B1 1D 00 00 00 0F 50 41 43 45 (.....±.....PACE 
4D 42 4C 41 48         MBLAH    

4.Server HTTP 401 त्रुटि के साथ प्रतिक्रिया करता है और शीर्ष लेख जारी रखने के लिए उत्साह बातचीत:

A1 81 CE 30 81 CB A0 03 0A 01 01 A1 0C 06 0A 2B ¡Î0Ë ....¡...+ 
06 01 04 01 82 37 02 02 0A A2 81 B5 04 81 B2 4E ....7...¢µ.²N 
54 4C 4D 53 53 50 00 02 00 00 00 08 00 08 00 38 TLMSSP.........8 
00 00 00 15 C2 89 E2 B0 3B BE 20 45 33 FD 92 80 ....Ââ°;¾ E3ý 
04 E7 01 00 00 00 00 72 00 72 00 40 00 00 00 06 .ç[email protected] 
01 B1 1D 00 00 00 0F 42 00 4C 00 41 00 48 00 02 .±.....B.L.A.H.. 
00 08 00 42 00 4C 00 41 00 48 00 01 00 0A 00 50 ...B.L.A.H.....P 
00 41 00 43 00 45 00 4D 00 04 00 10 00 62 00 6C .A.C.E.M.....b.l 
00 61 00 68 00 2E 00 63 00 6F 00 6D 00 03 00 1C .a.h...c.o.m.... 
00 50 00 61 00 63 00 65 00 6D 00 2E 00 62 00 6C .P.a.c.e.m...b.l 
00 61 00 68 00 2E 00 63 00 6F 00 6D 00 05 00 10 .a.h...c.o.m.... 
00 62 00 6C 00 61 00 68 00 2E 00 63 00 6F 00 6D .b.l.a.h...c.o.m 
00 07 00 08 00 5D B3 C5 9A 0F 17 D1 01 00 00 00 .....]³Å..Ñ.... 
00            .    

5.Client भेजता प्राधिकरण शीर्षलेख:

A1 77 30 75 A0 03 0A 01 01 A2 5A 04 58 4E 54 4C ¡w0u ....¢Z.XNTL 
4D 53 53 50 00 03 00 00 00 00 00 00 00 58 00 00 MSSP.........X.. 
00 00 00 00 00 58 00 00 00 00 00 00 00 58 00 00 .....X.......X.. 
00 00 00 00 00 58 00 00 00 00 00 00 00 58 00 00 .....X.......X.. 
00 00 00 00 00 58 00 00 00 15 C2 88 E2 06 01 B1 .....X....Ââ..± 
1D 00 00 00 0F C0 BD 0C 5B F5 F9 35 FE 78 6D 08 .....À½.[õù5þxm. 
BF 7B D9 CC E3 A3 12 04 10 01 00 00 00 F5 17 A7 ¿{ÙÌã£.......õ.§ 
50 2D 22 9A 84 00 00 00 00      P-"....  

6. सर्वर HTTP 200 और ne के साथ प्रतिक्रिया करता है gotiate हैडर:

A1 1B 30 19 A0 03 0A 01 00 A3 12 04 10 01 00 00 ¡.0. ....£...... 
00 43 87 E0 88 C1 36 E3 A9 00 00 00 00   .CàÁ6ã©.... 

अब अगर मैं एक सेवा मैं लगभग समान प्रतिक्रियाएं मिल जाएगा के रूप में आवेदन चलाते हैं, लेकिन AcceptSecurityContext कदम # 6 पर असफल और SEC_E_INVALID_HANDLE त्रुटि लौटाएगा। मुझे आश्चर्य है कि अगर मैं एक ही एप्लिकेशन चलाता हूं और उसी उपयोगकर्ता को सेवा लॉगऑन पहचान के रूप में निर्दिष्ट करता हूं तो यह क्यों विफल होगा? क्या यह किसी भी तरह से सत्र 0 अलगाव से संबंधित हो सकता है? इसके अलावा इसे बेहतर तरीके से समस्या निवारण का कोई तरीका भी है, मुझे ईवेंट व्यूअर में कोई त्रुटि संदेश नहीं दिखाई देता है और अमान्य हैंडल त्रुटि गुम होने के बारे में बहुत कुछ नहीं कहती है।

यहाँ सर्वर कोड को प्रमाणित करने के लिए है:

public static WinAuthResult Authenticate(string clientId, byte[] clientTokenBytes, string securityPackage, ILogger logger) 
{ 
    if (clientTokenBytes == null || clientTokenBytes.Length == 0) 
    { 
     ClearContext(clientId); 
     throw new Win32Exception(Secur32.SEC_E_INVALID_TOKEN); 
    } 

    var serverCredExpiry = new Secur32.SECURITY_INTEGER(); 
    var serverCredHandle = new Secur32.SecHandle(); 
    var acquireResult = Secur32.AcquireCredentialsHandle(null, securityPackage, Secur32.SECPKG_CRED_INBOUND, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, out serverCredHandle, out serverCredExpiry); 
    if (acquireResult != Secur32.SEC_E_OK) 
     throw new Win32Exception(acquireResult); 

    var oldContextExists = contexts.ContainsKey(clientId); 
    var oldContextHandle = GetContextHandle(clientId); 
    var newContextHandle = new Secur32.SecHandle(); 
    var clientToken = new Secur32.SecBufferDesc(clientTokenBytes); 
    var outputToken = new Secur32.SecBufferDesc(61440); 
    var contextAttributes = (uint)0; 
    var outputCresExpiry = new Secur32.SECURITY_INTEGER(); 

    int acceptResult; 
    if (!oldContextExists) 
    { 
     acceptResult = Secur32.AcceptSecurityContext(
      ref serverCredHandle, 
      IntPtr.Zero, 
      ref clientToken, 
      0, 
      Secur32.SECURITY_NATIVE_DREP, 
      ref newContextHandle, 
      ref outputToken, 
      out contextAttributes, 
      out outputCresExpiry); 
    } 
    else 
    { 
     acceptResult = Secur32.AcceptSecurityContext(
      ref serverCredHandle, 
      ref oldContextHandle, 
      ref clientToken, 
      0, 
      Secur32.SECURITY_NATIVE_DREP, 
      ref newContextHandle, 
      ref outputToken, 
      out contextAttributes, 
      out outputCresExpiry); 
    } 

    if (acceptResult == Secur32.SEC_E_OK) 
    { 
     ClearContext(clientId); 
     return new WinAuthResult(false, outputToken.GetSecBufferByteArray()); 
    } 
    else if (acceptResult == Secur32.SEC_I_CONTINUE_NEEDED) 
    { 
     contexts[clientId] = newContextHandle; 
     return new WinAuthResult(true, outputToken.GetSecBufferByteArray()); 
    } 
    else 
    { 
     ClearContext(clientId); 
     throw new Win32Exception(acceptResult); 
    } 
} 

दोनों ही मामलों में मैं एक ही मशीन जहां सर्वर चल रहा है से और एक ही डोमेन उपयोगकर्ता के साथ वेब पेज का उपयोग करने की कोशिश कर रहा हूँ। साथ ही मैं कंसोल ऐप और विंडोज़ सेवा चलाने के लिए एक ही डोमेन उपयोगकर्ता का उपयोग कर रहा हूं। यह समस्या Windows Server 2003 पर पुन: उत्पन्न नहीं होती है जो मुझे लगता है कि यह नई सुरक्षा सुविधाओं से संबंधित कुछ है।

उत्तर

2

थोड़ा समय हो गया है, लेकिन मुझे लगता है कि मैं इसी तरह के मुद्दों देखा जब लोड उपयोगकर्ता प्रोफ़ाइल आवेदन पूल की उन्नत सेटिंग में झूठी करने वाले थे। यह सेटिंग आईआईएस 7.0 के लिए नई है। प्रलेखन कहता है कि झूठा मान Windows Server 2003 व्यवहार से मेल खाता है लेकिन मुझे याद है कि प्रोफाइल लोड नहीं करना किसी भी तरह से एसएसपीआई उपप्रणाली के साथ हस्तक्षेप करता है। और आप सही हैं, वहां से कीमती छोटी त्रुटि रिपोर्टिंग है, मुझे कुछ हुप्स से कूदना पड़ा ताकि इसका उत्तर छेड़छाड़ की जा सके।

enter image description here

अद्यतन

उन कार्यों अंततः करबरोस ग्राहक कार्यान्वयन जो का एक बड़ा हिस्सा Lsass.exe प्रक्रिया में रहता है पर निर्भर हैं।पूरे उपप्रणाली की समस्या निवारण के संबंध में यहां एक अच्छा लिंक दिया गया है: http://blogs.msdn.com/b/canberrapfe/archive/2012/01/02/kerberos-troubleshooting.aspx

साथ ही, मुझे याद है कि एक बार जब ग्राहक को प्रमाणीकरण के आसपास समस्याएं होती हैं तो हम आखिरकार सर्वर 2008 पर चल रहे क्लाइंट के बीच कुछ प्रोटोकॉल विसंगति के लिए पता लगाते हैं (या ऐसा कुछ महत्वपूर्ण तथ्य यह है कि संस्करण 2003 से अधिक था) सर्वर 2003 पर चल रहे द्वितीयक डोमेन नियंत्रक से कनेक्ट किया गया था। इसे आगे नहीं पता था, क्लाइंट ने डीसी को अपग्रेड किया था।

अंतिम अद्यतन

ठीक है, मैं समस्या पुन: पेश करने में सक्षम था और मैं वास्तव में यह काम कर सकता था। Authenticate(string clientId, byte[] clientTokenBytes, string securityPackage, ILogger logger) विधि को AcceptSecurityContext पर पहली कॉल के कारण कम से कम दो बार कॉल किया जाता है SEC_I_CONTINUE_NEEDED लौटाता है। हर बार AuthenticateAcquireCredentialsHandle फ़ंक्शन को कॉल करके एक नया प्रमाण-पत्र संभालता है। यह मेरे लिए कंसोल और अंदरूनी सेवा के लिए स्थानीय सिस्टम के रूप में चल रहा है, लेकिन यह नहीं कि सेवा डोमेन खाते के तहत चल रही है, जैसा कि आपने कहा था।

तो, मैंने AcquireCredentialsHandle को Authenticate से कॉल किया ताकि मैं इसे एक बार प्राप्त कर सकूं और फिर आने वाली कॉल के लिए पुन: उपयोग कर सकूं। उसने मेरे लिए सेवा तय की।

संबंधित नोट पर, आपको FreeCredentialsHandle कॉल का उपयोग करके क्रेडेंशियल्स हैंडल मुक्त करना चाहिए, अन्यथा आप lsass.exe में मेमोरी लीक प्राप्त कर सकते हैं जिसके लिए आपको सर्वर को पुनरारंभ करने की आवश्यकता होगी। AcquireCredentialsHandle

+0

की MSDN विवरण में टिप्पणियां अनुभाग देखें आपकी प्रतिक्रिया के लिए धन्यवाद। शुरुआत में मैंने इस मुद्दे को टॉमकैट + वफ़ल फ़िल्टर के साथ पुन: उत्पन्न किया और बाद में स्वयं को लिखित HTTP सर्वर के साथ सी # पर एक छोटा सा उदाहरण बनाने का निर्णय लिया जो केवल क्लाइंट हेडर निकालता है और एसएसपीआई को कॉल करता है। दोनों मामलों में मुझे वही व्यवहार मिला - एपसेप्ट सेक्योरिटी कॉन्टेक्स्ट विफल रहा था जब ऐप सेवा के रूप में चल रहा था। दुर्भाग्य से मैं आईआईएस उन्नत सेटिंग्स का उपयोग नहीं कर सकता क्योंकि आखिर में मुझे इसे टॉमकैट के लिए काम करने की ज़रूरत है। अद्यतन के बारे में – username

+0

। प्रोटोकॉल पर बातचीत करना जरूरी नहीं है कि केर्बेरोस का उपयोग करें और मुझे लगता है कि मेरे मामले में एनटीएलएम का उपयोग तब किया जाता है जब मैं उसी सर्वर से लॉग इन करता हूं (जब मैंने अन्य टूल्स का परीक्षण किया तो वे समान परिणाम दे रहे थे और एनटीएलएम की रिपोर्ट कर रहे थे)। अगर मैं दूरस्थ रूप से लॉग इन करता हूं या आईपी पते का उपयोग करने की कोशिश करता हूं या इसे कंसोल ऐप के रूप में चलाता हूं तो मुझे किसी भी समस्या का अनुभव नहीं होता है। एकमात्र मामला जो काम नहीं करता है, इस ऐप को सेवा के रूप में चला रहा है। ऐसा लगता है कि सेवाओं के लिए कुछ प्रतिबंध या विशेषाधिकार थे जिन्हें मुझे बदलने की जरूरत है। – username

+0

आपके अंतिम अपडेट ने मेरी समस्या हल की। आपको बहुत - बहुत धन्यवाद! – username

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