2015-11-04 16 views
6

Tôi có một máy chủ HTTP đơn giản xác thực khách hàng bằng giao thức Thương lượng. Nó sử dụng các cuộc gọi SSPI để có được các thông tin máy chủ và thiết lập bối cảnh bảo mật. Máy chủ nằm trong miền và đang chạy thay mặt cho người dùng miền. Mọi thứ hoạt động tốt và tôi nhận được phản hồi HTTP 200 nếu tôi khởi động máy chủ ở chế độ bảng điều khiển. Tuy nhiên khi tôi chạy nó như một dịch vụ tôi nhận được lỗi SEC_E_INVALID_HANDLE. Đây là những gì xảy ra khi tôi bắt đầu nó ở chế độ điều khiển:AcceptSecurityContext không thành công khi ứng dụng đang chạy dưới dạng dịch vụ

1.Client gửi yêu cầu HTTP GET http://localhost:8082

2.Server đáp ứng với WWW-Authenticate: Negotiate tiêu đề.

3.Client gửi Authorization header và bao gồm các dữ liệu sau:

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 đáp ứng với HTTP 401 lỗi và thương lượng tiêu đề khiến để tiếp tục:

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 gửi Authorization tiêu đề:

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.Server trả lời bằng HTTP 200 và ne phần đầu 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ã©.... 

Bây giờ nếu tôi chạy các ứng dụng như một dịch vụ tôi sẽ nhận được phản ứng gần như giống hệt nhau, nhưng AcceptSecurityContext sẽ thất bại trên bướC# 6 và trả về lỗi SEC_E_INVALID_HANDLE. Tôi tự hỏi tại sao nó sẽ thất bại nếu tôi chạy cùng một ứng dụng và chỉ định cùng một người dùng như một bản ghi dịch vụ đăng nhập? Có thể nào đó bằng cách nào đó liên quan đến sự cô lập phiên 0? Ngoài ra còn có một cách để khắc phục sự cố tốt hơn, tôi không thấy bất kỳ thông báo lỗi nào trong trình xem sự kiện và lỗi xử lý không hợp lệ không nói nhiều về những gì bị thiếu.

Đây là mã máy chủ để xác thực:

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); 
    } 
} 

Trong cả hai trường hợp tôi đang cố gắng để truy cập trang web từ cùng một máy mà máy chủ đang chạy và với người sử dụng cùng một tên miền. Ngoài ra tôi đang sử dụng cùng một tên miền người dùng để chạy giao diện điều khiển ứng dụng và cửa sổ dịch vụ. Vấn đề này không thể sao chép được trên Windows Server 2003, điều này khiến tôi nghĩ rằng đó là một cái gì đó liên quan đến các tính năng bảo mật mới.

Trả lời

2

Đã lâu rồi nhưng tôi nghĩ tôi đã gặp sự cố tương tự khi Tải hồ sơ người dùng được đặt thành false trong Cài đặt nâng cao của Hồ bơi ứng dụng. Cài đặt đó là mới đối với IIS 7.0. Tài liệu này nói rằng giá trị false tương ứng với hành vi Windows Server 2003 nhưng tôi nhớ rằng không tải cấu hình can thiệp bằng cách nào đó với hệ thống con SSPI. Và bạn nói đúng, có rất ít lỗi báo cáo quý giá từ đó, tôi phải nhảy qua một số vòng để trêu chọc câu trả lời.

enter image description here

CẬP NHẬT

Những chức năng cuối cùng dựa trên Kerberos thực hiện khách hàng trong đó một phần lớn cư trú trong quá trình lsass.exe.Dưới đây là một liên kết tốt liên quan đến việc khắc phục sự cố toàn bộ hệ thống con: http://blogs.msdn.com/b/canberrapfe/archive/2012/01/02/kerberos-troubleshooting.aspx

Ngoài ra, tôi nhớ rằng một khi khách hàng gặp sự cố về xác thực mà chúng tôi truy tìm lần cuối vào một số giao thức không khớp giữa máy khách đang chạy trên Server 2008 (hoặc cái gì đó, quan trọng thực tế là phiên bản cao hơn 2003) kết nối với bộ điều khiển miền phụ đang chạy trên Server 2003. Không theo dõi nó thêm nữa, máy khách vừa nâng cấp DC.

CUỐI CÙNG CẬP NHẬT

OK, tôi đã có thể tạo lại vấn đề và tôi đã thực sự có thể làm cho nó làm việc. Phương thức Authenticate(string clientId, byte[] clientTokenBytes, string securityPackage, ILogger logger) của bạn được gọi ít nhất hai lần do cuộc gọi đầu tiên đến AcceptSecurityContext trả lại SEC_I_CONTINUE_NEEDED. Mỗi lần Authenticate nhận được thông tin đăng nhập mới xử lý bằng cách gọi hàm AcquireCredentialsHandle. Điều đó làm việc cho tôi trong giao diện điều khiển và dịch vụ bên trong chạy như LocalSystem, nhưng không phải là nếu dịch vụ đang chạy trong tài khoản miền, giống như bạn đã nói.

Vì vậy, tôi đã rút số AcquireCredentialsHandle gọi ra khỏi số Authenticate để tôi có thể lấy nó một lần và sau đó sử dụng lại cho các cuộc gọi đến tiếp theo. Điều đó đã sửa dịch vụ cho tôi.

Trên ghi chú liên quan, bạn nên giải phóng thông tin xác thực bằng cách sử dụng cuộc gọi FreeCredentialsHandle, nếu không bạn có thể bị rò rỉ bộ nhớ trong lsass.exe, yêu cầu bạn phải khởi động lại máy chủ. Xem Ghi chú phần trong mô tả MSDN của AcquireCredentialsHandle

+0

Cảm ơn bạn đã phản hồi. Ban đầu tôi đã sao chép vấn đề này với bộ lọc Tomcat + Waffle và sau đó quyết định tạo một ví dụ nhỏ trên C# với máy chủ HTTP tự viết chỉ trích xuất các tiêu đề của khách hàng và thực hiện các cuộc gọi đến SSPI. Trong cả hai trường hợp, tôi nhận được cùng một hành vi - AcceptSecurityContext không thành công khi ứng dụng đang chạy dưới dạng dịch vụ. Thật không may tôi không thể sử dụng các thiết lập nâng cao IIS vì cuối cùng tôi cần phải làm cho nó làm việc cho Tomcat. – username

+0

Về bản cập nhật. Giao thức thương lượng không nhất thiết phải sử dụng Kerberos và tôi nghĩ NTLM của tôi được sử dụng khi tôi đăng nhập từ cùng một máy chủ (khi tôi thử nghiệm các công cụ khác mà họ đã đưa ra kết quả tương tự và báo cáo NTLM). Tôi không gặp bất kỳ vấn đề gì nếu tôi đăng nhập từ xa hoặc cố gắng sử dụng địa chỉ IP hoặc chạy nó như một ứng dụng giao diện điều khiển. Trường hợp duy nhất không hoạt động là chạy ứng dụng này như một dịch vụ. Có vẻ như có những hạn chế hoặc đặc quyền nhất định đối với các dịch vụ mà tôi cần phải thay đổi. – username

+0

Bản cập nhật cuối cùng của bạn đã giải quyết được sự cố của tôi. Cảm ơn bạn rất nhiều! – username

Các vấn đề liên quan