Frage

Ich fragte eine Frage vor ein paar Tagen ( Zugriff auf SQL Server 2005 von einem nicht-Domäne-Maschine mit Windows-Authentifizierung ), die einige interessante bekam, aber nicht verwendbar Vorschläge. Ich möchte die Frage noch einmal fragen, aber deutlich machen, was meine Zwänge sind:

Ich habe eine Windows-Domäne, in dem eine Maschine SQL Server 2005 ausgeführt wird und konfiguriert ist, nur die Windows-Authentifizierung zu unterstützen. Ich mochte eine C # Client-Anwendung auf einem Rechner im gleichen Netzwerk laufen, aber das ist nicht auf der Domäne, und Zugriff auf eine Datenbank auf der SQL Server 2005-Instanz.

ICH KANN NICHT OS oder SQL Server-Benutzer auf jeder Maschine erstellen oder ändern, und ich kann nicht alle Änderungen an Berechtigungen oder Identitätswechsel machen, und ich kann nicht Gebrauch von runas machen.

Ich weiß, dass ich Perl und Java-Anwendungen schreiben, die auf die SQL Server-Datenbank verbinden können mit nur diese vier Parameter:. Servername, Datenbankname, Benutzername (in Form Domäne \ Benutzer) und das Kennwort

In C # Ich habe um verschiedene Dinge ausprobiert:

string connectionString = "Data Source=server;Initial Catalog=database;User Id=domain\user;Password=password";
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();

und versuchte Einstellung integrierte Sicherheit zu wahren und falschen, aber nichts scheint zu funktionieren. Ist das, was ich versuche einfach unmöglich in C # zu tun?

Vielen Dank für jede Hilfe, Martin

War es hilfreich?

Lösung

Wie Sie richtig sagen, JDBC oder Perl auf einem Linux-Rechner kann sowohl eine Verbindung zu einem SQL Server mit dem Windows-Authentifizierung und die Anmeldeinformationen, die auf Benutzer aus dem aktuell angemeldeten abweichen. Das gleiche gilt für Windows CE-Geräte , nebenbei bemerkt.

Ich denke, dass dies ist, dass dies nicht ein Problem von C #, aber der SQL Server OLE DB-Treiber. Ich denke, die oben genannten Methoden „so tun, als ein Windows-Rechner zu sein, mit einigen spezifischen Identifikationsdaten“ auf der Netzwerk-Ebene; eine Funktion, die der SQL Server OLE DB-Treiber fehlt. Somit wäre mein Vorschlag für eine Alternative zu suchen sein (vielleicht kommerziell?) OLE DB-Treiber, dass kann den Zugriff SQL Server-Datenbanken. Ich bin mir nicht sicher, ob es so etwas gibt, aber.

Andere Tipps

Ich hatte ein ähnliches Problem, wo ich ein Tool wurde zu schreiben, die auf einer Domain und Authentifizieren mit einem SQL-Server auf einer anderen Domäne mit einer gesicherten Verbindung auf einer Maschine laufen benötigt. Alles, was ich zu diesem Thema finden konnte, sagte, dass es nicht getan werden könnte. Stattdessen müssen Sie die Domäne, verwenden Sie SQL-Authentifizierung verbinden, mit einigen chap einlassen Kerberos genannt, oder Ihr Netzwerk Jungs Setup erhalten eine vertrauenswürdige Beziehung, ein paar Alternativen zu nennen.

Die Sache ist, ich wusste, dass ich bekommen konnte es in irgendeiner Weise arbeiten RUNAS mit, weil ich es mit SSMS bewiesen hatte:

C:\WINDOWS\system32\runas.exe /netonly /savecred /user:megacorp\joe.bloggs "C:\Program Files\Microsoft SQL Server\90\Tools\Binn\VSShell\Common7\IDE\SqlWb.exe"

Die / netonly Flagge erlaubte ich die exe mit den lokalen Anmeldeinformationen und den Zugriff auf das Netzwerk mit den Remote-Anmeldeinformationen ausführen, glaube ich, auf jeden Fall habe ich das Ergebnis stellt ich von dem Remote-Server erwartet. Das Problem war der Befehl runas macht es sehr schwierig, die Anwendung zu debuggen, und es roch nicht gut.

Schließlich fand ich diesen Artikel auf dem Code-Projekt , die über authentifizierten sprechen Active Directory zu manipulieren, hier ist die Hauptklasse, die die Identitätswechsel tut:

    using System;
    using System.Runtime.InteropServices;  // DllImport
    using System.Security.Principal; // WindowsImpersonationContext

    namespace TestApp
    {
        class Impersonator
        {
            // group type enum
            enum SECURITY_IMPERSONATION_LEVEL : int
            {
                SecurityAnonymous = 0,
                SecurityIdentification = 1,
                SecurityImpersonation = 2,
                SecurityDelegation = 3
            }

            // obtains user token
            [DllImport("advapi32.dll", SetLastError = true)]
            static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword,
                int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

            // closes open handes returned by LogonUser
            [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
            extern static bool CloseHandle(IntPtr handle);

            // creates duplicate token handle
            [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
                int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);

            WindowsImpersonationContext newUser;

            /// 
            /// Attempts to impersonate a user.  If successful, returns 
            /// a WindowsImpersonationContext of the new users identity.
            /// 
            /// Username you want to impersonate
            /// Logon domain
            /// User's password to logon with
            /// 
            public Impersonator(string sUsername, string sDomain, string sPassword)
            {
                // initialize tokens
                IntPtr pExistingTokenHandle = new IntPtr(0);
                IntPtr pDuplicateTokenHandle = new IntPtr(0);
                pExistingTokenHandle = IntPtr.Zero;
                pDuplicateTokenHandle = IntPtr.Zero;

                // if domain name was blank, assume local machine
                if (sDomain == "")
                    sDomain = System.Environment.MachineName;

                try
                {
                    const int LOGON32_PROVIDER_DEFAULT = 0;

                    // create token
                    // const int LOGON32_LOGON_INTERACTIVE = 2;
                    const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
                    //const int SecurityImpersonation = 2;

                    // get handle to token
                    bool bImpersonated = LogonUser(sUsername, sDomain, sPassword,
                        LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, ref pExistingTokenHandle);

                    // did impersonation fail?
                    if (false == bImpersonated)
                    {
                        int nErrorCode = Marshal.GetLastWin32Error();

                        // show the reason why LogonUser failed
                        throw new ApplicationException("LogonUser() failed with error code: " + nErrorCode);
                    }

                    bool bRetVal = DuplicateToken(pExistingTokenHandle, (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, ref pDuplicateTokenHandle);

                    // did DuplicateToken fail?
                    if (false == bRetVal)
                    {
                        int nErrorCode = Marshal.GetLastWin32Error();
                        CloseHandle(pExistingTokenHandle); // close existing handle

                        // show the reason why DuplicateToken failed
                        throw new ApplicationException("DuplicateToken() failed with error code: " + nErrorCode);
                    }
                    else
                    {
                        // create new identity using new primary token
                        WindowsIdentity newId = new WindowsIdentity(pDuplicateTokenHandle);
                        WindowsImpersonationContext impersonatedUser = newId.Impersonate();

                        newUser = impersonatedUser;
                    }
                }
                finally
                {
                    // close handle(s)
                    if (pExistingTokenHandle != IntPtr.Zero)
                        CloseHandle(pExistingTokenHandle);
                    if (pDuplicateTokenHandle != IntPtr.Zero)
                        CloseHandle(pDuplicateTokenHandle);
                }
            }

            public void Undo()
            {
                newUser.Undo();
            }
        }
    }

Um es zu benutzen Sie einfach:

Impersonator impersonator = new Impersonator("username", "domain", "password");

//Connect to and use SQL server

impersonator.Undo();

Ich habe in der Undo-Methode sonst der Imitator Objekt neigte Müll gesammelt zu bekommen. Ich habe auch den Code zu verwenden LOGON32_LOGON_NEW_CREDENTIALS geändert, aber dies war ein Sack und laufen, damit es funktioniert; Ich muss noch vollständig verstehen, was es tut, ich habe auf runas seine die gleiche wie die / netonly Flagge ein Gefühl. Ich bin auch der Konstruktor ein wenig brechen gehen.

Ist nutzlos Benutzername und Kennwort in Verbindungszeichenfolge angeben, weil die SQL-Authentifizierung bedeutet, und Sie bereits festgelegt, dass SQL Server akzeptiert nur die Windows-Authentifizierung.

Wenn der Server nicht erlaubt SQL-Authentifizierung dann die nur Möglichkeit zu verbinden ist die Windows-Authentifizierung zu verwenden, dh. IntegratedSecurity=true. Das bedeutet, dass Ihr Client authentifizieren wird als alles, was Berechtigungsnachweis den Prozess ausgeführt wird (oder zur Zeit imitierten wird).

Um die Windows-Authentifizierung arbeiten, müssen Sie eine der folgenden Optionen wählen:

  • Schließen Sie sich der Nicht-Domain-Maschine in einer Domäne (kann es sein, es ist eine eigene Domain!), Dass Trusts der Server-Domäne, dann den Client-Prozess als Domäne \ Anmeldeinformationen des Benutzers ausgeführt werden.
  • Verwenden Sie NTLM gespiegelt Konten: ein Paar lokale Benutzer auf dem Client und dem Server mit identischen Namen und Passwörter
  • .
  • Grant als ANONYMOUS Zugriff auf den SQL Server.

Wenn Sie das Client-Host Vertrauen der Server-Domäne machen können, noch können Sie hinzufügen NTLM gespiegelte Konten, und der SQL Server-Admin ist gesund genug, um nicht ANONYMOUS zu ermöglichen, dann werden Sie nicht in der Lage sein, zu verbinden.

Sie müssen configure SQL Server SQL Server-Authentifizierung zu ermöglichen, Verwendung, dh die Authentifizierung Benutzername und Passwort.

Sie können nicht von Domain Benutzername / Passwort ‚wie‘ Server-Authentifizierung authentifizieren, das heißt angeben Domäne Benutzername / Passwort direkt an.

kann ich natürlich falsch sein, aber ich bin sicher, dass dies kein Problem von C # oder .NET. Wie können Sie auf SQL Server anmelden in Ihrem Perl oder Java-Anwendung ??

Ich gebe Ihnen die Java-Antwort, die ich bin besser vertraut mit: Ich verwende die jTDS JDBC-Treiber mit den vier oben genannten Parametern. Die Perl-Anwendung Ich weiß weniger über, aber auf einer Linux-Box ausgeführt wird, und ist in der Lage mit den gleichen Parametern zu verbinden. Ich kann nicht den SQL Server ändern SQL-Authentifizierung zu unterstützen.

Um Remus' Vorschläge zu beantworten, kann ich jede dieser drei Dinge nicht tun, schlägt er vor, und doch Java und Perl-Anwendungen sind in der Lage zu verbinden. Jede andere Ideen?

Danke, Martin

Hier ist der Beispielcode, dass ich von einem Nicht-Domäne-Rechner verbinden verwenden Sie die jTDS JDBC-Treiber verwenden:

Class.forName ( "net.sourceforge.jtds.jdbc.Driver") newInstance (). String url = "jdbc: jtds: sqlserver: // server / Datenbank; domain = Domain"; conn = DriverManager.getConnection (url, "user", "password");

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top