2015-11-04 124 views
6

我有一个简单的HTTP服务器,它使用协商协议验证客户端。它使用SSPI调用获取服务器凭证并建立安全上下文。服务器在域中并且代表域用户运行。一切工作正常,我得到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服务。该问题在Windows Server 2003上无法重现,这使我认为它与新的安全功能有关。

回答

2

这已经有一段时间,但我觉得我看到了类似的问题时,加载用户配置在应用程序池的高级设置中设置为。该设置对于IIS 7.0来说是新的。该文档确实说虚假值对应于Windows Server 2003的行为,但我记得不加载该配置文件以某种方式干涉SSPI子系统。你说得对,从那里可以得到宝贵的小错误报告,我不得不跳过一些环节来挑出答案。

enter image description here

UPDATE

这些功能最终依赖于其中的一个大的部分驻留在lsass.exe进程Kerberos客户端实现。下面是有关故障排除整个子系统一个很好的链接:http://blogs.msdn.com/b/canberrapfe/archive/2012/01/02/kerberos-troubleshooting.aspx

另外,我记得有一次一个客户端有大约认证,我们最终追踪到客户端之间的一些协议不匹配服务器2008(或类似的东西上运行的,重要的问题事实上该版本高于2003)连接到在Server 2003上运行的辅助域控制器。没有进一步追踪,客户端刚刚升级了DC。

最后更新

OK,我能够重现问题,实际上,我是能够使它发挥作用。您的Authenticate(string clientId, byte[] clientTokenBytes, string securityPackage, ILogger logger)方法会因第一次致电AcceptSecurityContext而返回SEC_I_CONTINUE_NEEDED而至少被调用两次。每次Authenticate通过调用AcquireCredentialsHandle函数获取新的凭证句柄。这对我在控制台和内部服务中运行的LocalSystem非常有用,但是如果服务在域帐户下运行,就像你说的那样。

所以,我把呼叫从Authenticate中拨出,这样我就可以获得一次,然后再用于随后的来电。为我修好了这项服务。

在相关说明中,您应该使用FreeCredentialsHandle调用来释放凭证句柄,否则可能会在lsass.exe中发生内存泄漏,这会要求您重新启动服务器。请参阅备注在MSDN说明AcquireCredentialsHandle

+0

部分谢谢您的回应。最初,我使用Tomcat + Waffle过滤器再现了这个问题,后来决定在C#上创建一个带有自写HTTP服务器的小例子,该服务器仅提取客户端标头并调用SSPI。在这两种情况下,我都得到了相同的行为 - 当应用程序作为服务运行时,AcceptSecurityContext失败。不幸的是,我不能使用IIS高级设置,因为最终我需要使它适用于Tomcat。 – username

+0

关于更新。协商协议不一定使用Kerberos,我认为在我使用NTLM时,我从同一台服务器登录(当我测试其他工具时,他们给出类似的结果并报告NTLM)。如果我远程登录或尝试使用IP地址或将其作为控制台应用运行,则不会遇到任何问题。唯一不起作用的情况是将此应用作为服务运行。它看起来好像对我需要更改的服务有某些限制或特权。 – username

+0

您的最新更新解决了我的问题。非常感谢! – username

相关问题