Domanda

Ho fatto una domanda un paio di giorni fa ( L'accesso a SQL Server 2005 da una macchina non-dominio utilizzando l'autenticazione di Windows ) che ha ottenuto alcuni interessanti, ma non i suggerimenti utilizzabili. Mi piacerebbe chiedere di nuovo la questione, ma mettere in chiaro quali sono i miei limiti sono:

Ho un dominio di Windows all'interno di cui una macchina è in esecuzione SQL Server 2005 e che è configurato per supportare solo l'autenticazione di Windows. Vorrei eseguire un'applicazione C # client su una macchina sulla stessa rete, ma che non è sul dominio, e accedere a un database per l'istanza di SQL Server 2005.

Non riesco a creare o modificare gli utenti del sistema operativo o SQL Server su entrambi i computer, e non posso apportare modifiche alle autorizzazioni o la rappresentazione, e non riesco a fare uso di runas.

So che posso scrivere applicazioni Perl e Java in grado di connettersi al database di SQL Server utilizzando solo questi quattro parametri:. Il nome del server, nome del database, nome utente (nella forma dominio \ utente) e la password

In C # Ho provato varie cose intorno:

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

e provato a regolare la sicurezza integrata a vero e falso, ma nulla sembra funzionare. È quello che sto cercando di fare semplicemente impossibile in C #?

Grazie per qualsiasi aiuto, Martin

È stato utile?

Soluzione

Come dici giustamente, JDBC o Perl su una macchina Linux può sia di connessione a uno SQL Server tramite autenticazione di Windows e le credenziali che si differenziano dal utente attualmente connesso. Lo stesso vale per i dispositivi Windows CE , tra l'altro.

Credo che questo è che questo non è un problema di C #, ma del driver di SQL Server OLE DB. Credo che i metodi di cui sopra "fingere di essere una macchina Windows utilizzando alcuni credenziali specifiche" a livello di rete; una caratteristica, che il driver di SQL Server OLE DB manca. Quindi, il mio suggerimento sarebbe quello di cercare un'alternativa (forse commerciale?) Del driver OLE DB che i database di accesso può SQL Server. Non sono sicuro se esiste una cosa del genere, però.

Altri suggerimenti

Ho avuto un problema simile in cui stavo scrivendo uno strumento che serve per funzionare su una macchina su un dominio e l'autenticazione con un server SQL su un altro dominio utilizzando una connessione di fiducia. Tutto quello che ho potuto trovare su questo argomento ha detto che non poteva essere fatto. Invece è necessario unire il dominio, l'autenticazione di SQL uso, mettersi in gioco con un tizio chiamato Kerberos, o il tuo tipi della rete di impostare un rapporto di fiducia, per citarne alcune alternative.

Il fatto è che sapevo che avrei potuto farlo funzionare in qualche modo utilizzando RUNAS perché avevo provata con SSMS:

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"

Il flag / netonly mi ha permesso di eseguire l'exe con le credenziali locali e l'accesso alla rete con le credenziali remote, credo, in ogni caso ho ottenuto il set di risultati che mi aspettavo dal server remoto. Il problema è stato il comando runas ha reso molto difficile eseguire il debug dell'applicazione, e non ha un buon odore.

Alla fine ho trovato questo articolo sul il progetto di codice che è stato parlando di autenticazione per manipolare Active Directory, Ecco la classe principale che fa la rappresentazione:

    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();
            }
        }
    }

Per utilizzarlo basta:

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

//Connect to and use SQL server

impersonator.Undo();

ho aggiunto nel metodo Undo altrimenti l'oggetto sosia tendeva ad ottenere garbage collection. Ho anche modificato il codice per utilizzare LOGON32_LOGON_NEW_CREDENTIALS ma questo era un poke e corsa per farlo funzionare; Ho ancora bisogno di comprendere appieno ciò che fa, ho la sensazione che la sua lo stesso come la bandiera / netonly su runas. Ho anche intenzione di abbattere il costruttore un po '.

È inutile specificare il nome utente e la password nella stringa di connessione, perché quelli implica l'autenticazione di SQL, e già specificato che SQL Server accetta solo l'autenticazione di Windows.

Se il server non consente l'autenticazione di SQL allora la solo Possibilità di collegamento è quello di utilizzare l'autenticazione di Windows, vale a dire. IntegratedSecurity=true. Il che significa che il client esegue l'autenticazione come qualunque credenziale è in esecuzione il processo (o viene attualmente impersonato).

Al fine di autenticazione di Windows per il lavoro, si deve scegliere una delle seguenti:

  • Unisciti alla non-dominio uniti macchina in un dominio (che può essere il proprio dominio!) Che i trust il dominio del server, quindi eseguire il processo client come dominio \ credenziali utente.
  • Usa NTLM rispecchiato conti: un paio di utenti locali sul client e il server con nome identico e password
  • .
  • Grant come l'accesso anonimo a SQL Server.

Se non è possibile effettuare la fiducia client host il dominio del server, né è possibile aggiungere NTLM rispecchiato conti, e l'amministratore di SQL Server è abbastanza sano di mente da non consentire ANONIMO allora non sarà in grado di connettersi.

Devi configurare SQL Server per consentire l'autenticazione di SQL Server , cioè l'autenticazione tramite username e password.

Non si può autenticare per dominio username / password 'come' l'autenticazione del server, vale a dire specificare direttamente dominio nome utente / password.

I può essere sbagliato, naturalmente, ma sono sicuro che questo non è un problema di C # o .NET. Come si può effettuare il login su SQL Server nell'applicazione Perl o Java ??

ti darò la risposta Java, che sono più familiarità con: Io uso il driver JDBC jTDS con i quattro parametri di cui sopra. L'applicazione Perl che conosco di meno, ma è in esecuzione su una macchina Linux, ed è in grado di connettersi con gli stessi parametri. Non posso cambiare lo SQL Server per supportare l'autenticazione di SQL.

Per rispondere a proposte Remus', non posso fare nessuna di queste tre cose egli suggerisce e le applicazioni Java e Perl ancora sono in grado di connettersi. Tutte le altre idee?

Grazie, Martin

E 'la possibilità di richiesta di credenziali ?

Ecco il codice di esempio che io uso per la connessione da una macchina non di dominio utilizzando il driver JDBC jTDS:

Class.forName ( "net.sourceforge.jtds.jdbc.Driver") newInstance ().; String url = "jdbc: jtds: sqlserver: // server / banca dati; domain = dominio"; conn = DriverManager.getConnection (url, "utente", "password");

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top