当社は最近、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) に回避策がない限り、新しいライブラリを使用するためにすべての内部アプリケーションを更新する必要があることを意味します。今は本当に時間がないので、誰かがこれを機能させる方法を持っているなら、ぜひ聞いてみたい.