0

我们公司最近开始与一个合作伙伴开展业务,该合作伙伴正试图为我们提供一个基于 Web 的 RDP 连接到他们的系统。作为他们设置文档的一部分,他们要求我们更改工作站的本地网络安全策略:具体而言,将LAN Manager 身份验证级别设置从之前的发送 LM 和 NTLM 响应更改为仅发送 NTLMv2 响应。一旦我进行此更改并对gpupdate /force工作站进行更改(然后显示“正确”设置的策略),我可以 RDP 进入我们新合作伙伴的服务器就好了,但我所有连接到 PostgreSQL 数据库文件的应用程序都出现以下错误:

FATAL: XX000: could not accept SSPI security context

我构建了一个临时应用程序来测试 Visual Studio 中的连接,代码如下(网络详细信息已编辑):

Imports Npgsql
Imports System.DirectoryServices

Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim PGUserName As String
        Dim PGDB As NpgsqlConnection = Nothing
        Dim PGConnection As NpgsqlConnectionStringBuilder
        Dim PGCommand As NpgsqlCommand = Nothing
        Dim PGAdapter As NpgsqlDataAdapter = Nothing
        Dim TestSQL As String = String.Empty
        Dim TestData As New DataTable

        PGUserName = GetActiveDirectoryUsername()

        TestSQL = "SELECT * FROM testdb"
        PGConnection = New NpgsqlConnectionStringBuilder

        With PGConnection
            NpgsqlEventLog.Level = LogLevel.Debug
            NpgsqlEventLog.LogName = "C:\TEST\NPGSQLEVENTLOG.TXT"
            .Host = "<PGSQLSERVER>"
            .Port = <PORT>
            .UserName = PGUserName
            .IntegratedSecurity = True
            .Database = "testing"
        End With

        PGDB = New NpgsqlConnection(PGConnection.ConnectionString)

       Try
            PGDB.Open()
            PGCommand = New NpgsqlCommand(TestSQL, PGDB)
            PGAdapter = New NpgsqlDataAdapter(PGCommand)
            PGAdapter.Fill(TestData)
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        Finally
            If Not PGAdapter Is Nothing Then
                PGAdapter.Dispose()
            End If

            If Not PGCommand Is Nothing Then
                PGCommand.Dispose()
            End If

            If PGDB.State <> ConnectionState.Closed Then
                PGDB.Close()
            End If

            If Not PGDB Is Nothing Then
                PGDB.Dispose()
            End If

            If Not TestData Is Nothing Then
                TestData.Dispose()
            End If
        End Try
    End Sub

    Friend Function GetDirectoryEntry() As DirectoryEntry
        Dim dirEntry As DirectoryEntry = New DirectoryEntry()
        dirEntry.Path = "LDAP://<ADSERVERIP>/DC=<DOMAIN>"
        Return dirEntry
    End Function

    Friend Function GetActiveDirectoryUsername() As String
        Try
            Dim MyDirectory As DirectoryEntry = GetDirectoryEntry()
            Dim search As New DirectorySearcher(MyDirectory)

            search.Filter = String.Format("(&(SAMAccountName={0}))", Environment.UserName)

            'Use the .FindOne() Method to stop as soon as a match is found
            Dim result As SearchResult = search.FindOne()

            If result Is Nothing Then
                Return ""
            Else
                Return result.Properties("samaccountname").Item(0).ToString
            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Active Directory Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1)
            Return ""
        End Try
    End Function
End Class

如果我在发送 LM 和 NTLM 响应上设置LAN Manager 身份验证级别,所有这些代码都可以完美运行,但如果我将其更改为仅根据我们的新合作伙伴的要求发送 NTLMv2 响应,它会在语句中引发异常。从调试日志:PGDB.Open()

2/22/16 12:32:58 PM 11452   Debug   Entering NpgsqlConnection.NpgsqlConnection(NpgsqlConnection())
2/22/16 12:32:58 PM 11452   Debug   ConnectionString Option: HOST = <PGSQLSERVER>
2/22/16 12:32:58 PM 11452   Debug   ConnectionString Option: PORT = <PORT>
2/22/16 12:32:58 PM 11452   Debug   ConnectionString Option: PROTOCOL = 3
2/22/16 12:32:58 PM 11452   Debug   ConnectionString Option: DATABASE = testing
2/22/16 12:32:58 PM 11452   Debug   ConnectionString Option: USER ID = <PGSQLUSERNAME>
2/22/16 12:32:58 PM 11452   Debug   ConnectionString Option: SSL = False
2/22/16 12:32:58 PM 11452   Debug   ConnectionString Option: SSLMODE = Disable
2/22/16 12:32:58 PM 11452   Debug   ConnectionString Option: TIMEOUT = 15
2/22/16 12:32:58 PM 11452   Debug   ConnectionString Option: POOLING = True
2/22/16 12:32:58 PM 11452   Debug   ConnectionString Option: CONNECTIONLIFETIME = 15
2/22/16 12:32:58 PM 11452   Debug   ConnectionString Option: MINPOOLSIZE = 1
2/22/16 12:32:58 PM 11452   Debug   ConnectionString Option: MAXPOOLSIZE = 20
2/22/16 12:32:58 PM 11452   Debug   ConnectionString Option: SYNCNOTIFICATION = False
2/22/16 12:32:58 PM 11452   Debug   ConnectionString Option: COMMANDTIMEOUT = 20
2/22/16 12:32:58 PM 11452   Debug   ConnectionString Option: ENLIST = False
2/22/16 12:32:58 PM 11452   Debug   ConnectionString Option: PRELOADREADER = False
2/22/16 12:32:58 PM 11452   Debug   ConnectionString Option: USEEXTENDEDTYPES = False
2/22/16 12:32:58 PM 11452   Debug   ConnectionString Option: INTEGRATED SECURITY = True
2/22/16 12:32:58 PM 11452   Debug   ConnectionString Option: COMPATIBLE = 2.0.11.92
2/22/16 12:32:58 PM 11452   Debug   Entering NpgsqlConnection.Open()
2/22/16 12:32:58 PM 11452   Debug   Get NpgsqlClosedState.Instance
2/22/16 12:32:58 PM 11452   Debug   Get NpgsqlClosedState.Instance
2/22/16 12:32:58 PM 11452   Debug   Entering NpgsqlClosedState.Open()
2/22/16 12:32:58 PM 11452   Debug   Attempt to connect to '<PGSQLSERVERIP>'.
2/22/16 12:32:58 PM 11452   Normal  Connected to: <PGSQLSERVER>:<PORT>.
2/22/16 12:32:58 PM 11452   Debug   Entering NpgsqlStartupPacket.NpgsqlStartupPacket()
2/22/16 12:32:58 PM 11452   Debug   Entering NpgsqlStartupPacket.WriteToStream()
2/22/16 12:32:58 PM 11452   Debug   Entering NpgsqlStartupPacket.WriteToStream_Ver_3()
2/22/16 12:32:58 PM 11452   Debug   Entering PGUtil.WriteString()
2/22/16 12:32:58 PM 11452   Debug   String written: user.
2/22/16 12:32:58 PM 11452   Debug   Entering PGUtil.WriteString()
2/22/16 12:32:58 PM 11452   Debug   String written: <PGSQLUSERNAME>.
2/22/16 12:32:58 PM 11452   Debug   Entering PGUtil.WriteString()
2/22/16 12:32:58 PM 11452   Debug   String written: database.
2/22/16 12:32:58 PM 11452   Debug   Entering PGUtil.WriteString()
2/22/16 12:32:58 PM 11452   Debug   String written: testing.
2/22/16 12:32:58 PM 11452   Debug   Entering PGUtil.WriteString()
2/22/16 12:32:58 PM 11452   Debug   String written: DateStyle.
2/22/16 12:32:58 PM 11452   Debug   Entering PGUtil.WriteString()
2/22/16 12:32:58 PM 11452   Debug   String written: ISO.
2/22/16 12:32:58 PM 11452   Debug   Entering NpgsqlState.ProcessBackendResponses()
2/22/16 12:32:58 PM 11452   Debug   AuthenticationRequest message received from server.
2/22/16 12:32:58 PM 11452   Debug   Entering NpgsqlStartupState.Authenticate()
2/22/16 12:32:58 PM 11452   Debug   Entering NpgsqlPasswordPacket.NpgsqlPasswordPacket()
2/22/16 12:32:58 PM 11452   Debug   Entering NpgsqlPasswordPacket.WriteToStream()
2/22/16 12:32:58 PM 11452   Debug   Entering PGUtil.WriteBytes()
2/22/16 12:32:58 PM 11452   Debug   Unable to find resource string Log_BytesWritten for class PGUtil
2/22/16 12:32:58 PM 11452   Debug   AuthenticationRequest message received from server.
2/22/16 12:32:58 PM 11452   Debug   Entering NpgsqlStartupState.Authenticate()
2/22/16 12:32:58 PM 11452   Debug   Entering NpgsqlPasswordPacket.NpgsqlPasswordPacket()
2/22/16 12:32:58 PM 11452   Debug   Entering NpgsqlPasswordPacket.WriteToStream()
2/22/16 12:32:58 PM 11452   Debug   Entering PGUtil.WriteBytes()
2/22/16 12:32:58 PM 11452   Debug   Unable to find resource string Log_BytesWritten for class PGUtil
2/22/16 12:32:58 PM 11452   Debug   Entering PGUtil.ReadString()
2/22/16 12:32:58 PM 11452   Debug   Get NpgsqlEventLog.LogLevel
2/22/16 12:32:58 PM 11452   Debug   String read: FATAL.
2/22/16 12:32:58 PM 11452   Debug   Entering PGUtil.ReadString()
2/22/16 12:32:58 PM 11452   Debug   Get NpgsqlEventLog.LogLevel
2/22/16 12:32:58 PM 11452   Debug   String read: XX000.
2/22/16 12:32:58 PM 11452   Debug   Entering PGUtil.ReadString()
2/22/16 12:32:58 PM 11452   Debug   Get NpgsqlEventLog.LogLevel
2/22/16 12:32:58 PM 11452   Debug   String read: could not accept SSPI security context.
2/22/16 12:32:58 PM 11452   Debug   Entering PGUtil.ReadString()
2/22/16 12:32:58 PM 11452   Debug   Get NpgsqlEventLog.LogLevel
2/22/16 12:32:58 PM 11452   Debug   String read: The token supplied to the function is invalid
 (80090308).
2/22/16 12:32:58 PM 11452   Debug   Entering PGUtil.ReadString()
2/22/16 12:32:58 PM 11452   Debug   Get NpgsqlEventLog.LogLevel
2/22/16 12:32:58 PM 11452   Debug   String read: src\backend\libpq\auth.c.
2/22/16 12:32:58 PM 11452   Debug   Entering PGUtil.ReadString()
2/22/16 12:32:58 PM 11452   Debug   Get NpgsqlEventLog.LogLevel
2/22/16 12:32:58 PM 11452   Debug   String read: 1024.
2/22/16 12:32:58 PM 11452   Debug   Entering PGUtil.ReadString()
2/22/16 12:32:58 PM 11452   Debug   Get NpgsqlEventLog.LogLevel
2/22/16 12:32:58 PM 11452   Debug   String read: pg_SSPI_error.
2/22/16 12:32:58 PM 11452   Debug   ErrorResponse message from Server: could not accept SSPI security context.
2/22/16 12:32:58 PM 11452   Normal  An NpgsqlException occured: FATAL: XX000: could not accept SSPI security context.
2/22/16 12:33:02 PM 11452   Debug   Entering NpgsqlConnection.Dispose()
2/22/16 12:33:03 PM 11452   Debug   Entering NpgsqlConnection.Close()

奇怪的是,如果我尝试使用 SSPI 使用 PGAdmin III 进行连接,则没有错误。我重新启动了服务器上的 PostgreSQL 服务(以防万一),但仍然出现同样的错误。我什至重新启动了整个服务器,但错误仍然存​​在。

现在,如果我将本地网络安全策略设置改回发送 LM & NTLM 响应,应用程序可以正常工作,但我们无法建立与合作伙伴系统的 RDP 连接。我什至尝试将策略设置更改为发送 LM 和 NTLM - 如果协商使用 NTLMv2 会话安全。同样,我的应用程序将无错误地连接到数据库,但 RDP 连接失败。

我想问题归结为:当本地网络安全策略的LAN 管理器身份验证级别设置配置为仅发送 NTLMv2 响应时,有谁知道如何让 Npgsql 连接到 PostgreSQL 数据库?由于其他一切似乎都正常工作(据我所知),这似乎是失败的地方。

编辑:由于我在 Visual Studio 2015 中工作,因此我尝试通过 NuGet 控制台更新我正在使用的 Npgsql 版本。这将库更新到版本 3.0.5.0,我在Send NTLMv2 response only设置下再次测试了连接。这次应用程序的连接似乎工作正常。可以肯定的是,我删除了 3.0.5.0 引用并添加了我的旧版本(显然我在 2.0.11.92 -是的,是的......我知道)并再次测试,这给了我和以前一样的错误。

看起来导致问题的任何原因都已通过对 Npgsql 库的后续更新得到解决。当然,这意味着,除非我正在使用的版本 (2.0.11.92) 有解决方法,否则我将不得不更新我所有的内部应用程序以使用更新的库。我现在真的没有时间做所有这些,所以如果有人有办法完成这项工作,我很想听听。

4

1 回答 1

1

@G_Hosa_Phat。我记得我们对 ntlm 支持做了很大的修改,因为你可以通过测试最近的 3.0.x 版本来检查它并让它工作......

没有配置选项可以更改您可以使用的 ntlm 身份验证的行为。我认为你真的需要更新你的图书馆。

但我建议您更新到最新的 2.x 版本,而不是 3.0.x,因为 3.0.x 的更改超出了 ntlm 支持,它可能会破坏您现有的系统。

很抱歉给你这个坏消息。:(

我希望它有所帮助。

于 2016-02-24T17:55:19.207 回答