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

LAN Manager 認証レベルを [ Send LM & NTLM response]に設定したままにしておくと、このコードはすべて完全に機能しますが、新しいパートナーが必要とする場合にのみ [Send NTLMv2 response]に変更すると、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 接続を確立できません。ポリシー設定を [ Send LM & NTLM - use NTLMv2 session security if negotiation]に変更してみました。ここでも、アプリケーションはエラーなしでデータベースに接続しますが、RDP 接続は失敗します。

質問はこれに要約されると思います: ローカル ネットワーク セキュリティ ポリシーのLAN Manager 認証レベル設定がNTLMv2 応答のみを送信するように構成されているときに、Npgsql を PostgreSQL データベースに接続する方法を知っている人はいますか? 他のすべては正常に動作しているように見えるので (私が知る限り)、これが失敗のポイントのようです。

編集:私は Visual Studio 2015 で作業しているので、使用していた Npgsql のバージョンを NuGet コンソールから更新してみました。これにより、ライブラリがバージョン 3.0.5.0 に更新され、[ NTLMv2 応答のみを送信]設定で接続を再度テストしました。今回は、アプリケーションの接続は正常に機能しているようです。念のため、3.0.5.0 参照を削除し、以前のバージョンを追加し直して (どうやら私は 2.0.11.92 を使用しているようです -ええ、ええ... 知っています)、再度テストしたところ、以前と同じエラーが発生しました。

Npgsql ライブラリへのその後の更新により、問題の原因が解決されたようです。もちろん、これは、使用しているバージョン (2.0.11.92) に回避策がない限り、新しいライブラリを使用するためにすべての内部アプリケーションを更新する必要があることを意味します。今は本当に時間がないので、誰かがこれを機能させる方法を持っているなら、ぜひ聞いてみたい.

4

1 に答える 1

1

@G_Hosa_Phat。最近の 3.0.x バージョンをテストして動作させることで確認できるように、ntlm サポートを大幅に作り直したのを覚えています...

使用できる ntlm 認証の動作を変更する構成オプションはありません。ライブラリを更新する必要があると思います。

ただし、3.0.x の変更は ntlm サポートを超えており、既存のシステムが壊れる可能性があるため、3.0.x ではなく、最新の 2.x バージョンに更新することをお勧めします。

この悪い知らせを伝えて申し訳ありません。:(

お役に立てば幸いです。

于 2016-02-24T17:55:19.207 に答える