Question

J'ai posé une question il y a quelques jours ( L'accès à SQL Server 2005 à partir d'une machine non-domaine à l'aide d'authentification Windows) qui a obtenu un peu intéressant, mais pas des suggestions utilisables. Je voudrais demander à nouveau la question, mais fait comprendre ce que mes contraintes sont:

J'ai un domaine Windows dans lequel une machine exécute SQL Server 2005 et qui est configuré pour supporter uniquement l'authentification Windows. Je voudrais lancer une application client C # sur une machine sur le même réseau, mais qui ne figure pas dans le domaine, et accéder à une base de données sur l'instance SQL Server 2005.

JE NE PEUX PAS créer ou modifier OS ou les utilisateurs SQL Server sur la machine ou l'autre, et je ne peux apporter des modifications aux autorisations ou usurpation d'identité, et je ne peux utiliser runas.

Je sais que je peux écrire des applications Perl et Java qui peuvent se connecter à la base de données SQL Server en utilisant uniquement ces quatre paramètres:. Nom du serveur, le nom de base de données, nom d'utilisateur (dans le domaine \ utilisateur) et le mot de passe

En C # J'ai essayé différentes choses:

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

et essayé de définir la sécurité intégrée à vrai et faux, mais rien ne semble fonctionner. Est-ce que je suis en train de faire tout simplement impossible en C #?

Merci pour toute aide, Martin

Était-ce utile?

La solution

Comme vous le dites correctement, JDBC ou Perl sur une machine Linux peut à la fois connecter à un serveur SQL en utilisant l'authentification Windows et les informations d'identification qui diffèrent de l'utilisateur actuellement connecté. en est de même pour les appareils Windows CE , par la manière.

Je pense que cela est que ce n'est pas une question de C #, mais du pilote OLE DB SQL Server. Je suppose que les méthodes mentionnées ci-dessus « faire semblant d'être une machine Windows en utilisant des informations d'identification spécifiques » au niveau du réseau; une caractéristique que le pilote OLE DB SQL Server ne dispose pas. Ainsi, ma suggestion serait de chercher une alternative pilote OLE DB (peut-être commercial?) Que l'accès peut bases de données SQL Server. Je ne sais pas si une telle chose existe, cependant.

Autres conseils

J'ai eu un problème similaire où je rédigeais un outil qui avait besoin de fonctionner sur une machine sur un domaine et authentifier avec un serveur SQL sur un autre domaine à l'aide d'une connexion sécurisée. Tout ce que je pouvais trouver sur le sujet a dit qu'il ne pouvait pas être fait. Au lieu de cela, vous devez joindre le domaine, utilisez l'authentification SQL, impliquez avec un certain type appelé Kerberos, ou vos gars de réseau pour installer une relation de confiance, pour ne citer que quelques alternatives.

La chose est que je savais que je pouvais le faire fonctionner à l'aide d'une certaine façon RUNAS parce que je l'avais prouvé avec 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"

Le / drapeau netonly me permettait d'exécuter l'exe avec les pouvoirs locaux et l'accès au réseau avec les informations d'identification à distance, je pense, de toute façon je suis le jeu de résultats que je pensais du serveur distant. Le problème a été prescris a rendu très difficile runas pour déboguer l'application, et il n'a pas une bonne odeur.

Finalement, j'ai trouvé cet article sur le projet de code qui parlait de authentifiant pour manipuler active Directory, Voici la classe principale qui fait l'usurpation d'identité:

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

Pour l'utiliser simplement:

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

//Connect to and use SQL server

impersonator.Undo();

I ajouté dans la méthode d'annulation sinon l'objet imitateur avait tendance à obtenir des déchets collectés. J'ai aussi modifié le code à utiliser LOGON32_LOGON_NEW_CREDENTIALS mais ce fut un coup de coude et courir pour le faire fonctionner; Je dois encore comprendre ce qu'il fait, je sens son même que le / drapeau netonly sur runas. Je vais aussi briser le constructeur un peu.

est inutile de spécifier le nom d'utilisateur et mot de passe dans la chaîne de connexion, car l'authentification SQL ceux qui impliquent, et vous avez déjà spécifié que SQL Server accepte uniquement l'authentification Windows.

Si le serveur ne permet pas l'authentification SQL puis uniquement possibilité de connexion est d'utiliser l'authentification Windows, à savoir. IntegratedSecurity=true. Ce qui signifie que votre client s'authentifient tout diplôme est en cours d'exécution du processus (ou est actuellement personnifié).

Pour l'authentification Windows au travail, vous devez choisir une des options suivantes:

  • Rejoignez la machine joint non-domaine dans un domaine (il peut être son propre domaine!) Qui approuve le domaine du serveur, puis exécutez le processus client en tant que domaine \ informations d'identification utilisateur.
  • Utiliser NTLM miroir comptes: une paire d'utilisateurs locaux sur le client et le serveur avec un nom identique et les mots de passe
  • .
  • Grant l'accès ANONYME à SQL Server.

Si vous ne pouvez pas la confiance d'accueil du client le domaine du serveur, et vous ne pouvez ajouter NTLM miroir des comptes, et l'administrateur SQL Server est assez sain d'esprit de ne pas permettre ANONYME alors vous ne serez pas en mesure de se connecter.

Vous devez configurer SQL Server pour permettre l'authentification SQL Server , à savoir l'authentification par nom d'utilisateur et mot de passe.

Vous ne pouvez pas authentifier par domaine nom d'utilisateur / mot de passe « comme » authentification du serveur, à savoir spécifier domaine nom d'utilisateur / mot de passe directement.

Je peux me tromper bien sûr, mais je suis sûr que ce n'est pas un problème de C # ou .NET. Comment pouvez-vous ouvrir une session sur SQL Server dans votre application Perl ou Java ??

Je vais vous donner la réponse Java que je suis plus familier avec: J'utilise le pilote JDBC jTDS avec les quatre paramètres mentionnés ci-dessus. L'application Perl je connais moins, mais est en cours d'exécution sur une machine Linux, et est capable de se connecter avec les mêmes paramètres. Je ne peux pas changer le serveur SQL pour soutenir l'authentification SQL.

Pour répondre aux suggestions de Remus, je ne peux faire aucune de ces trois choses qu'il propose et encore des applications Java et Perl sont capables de se connecter. D'autres idées?

Merci, Martin

est-il une option invite des informations d'identification?

Voici le code exemple que j'utilise pour se connecter à partir d'une machine non-domaine à l'aide du pilote JDBC jTDS:

Class.forName ( "net.sourceforge.jtds.jdbc.Driver") newInstance (). Url: String = "jdbc: jtds: SQLServer: // serveur / base de données; domain = domaine"; conn = DriverManager.getConnection (url, "utilisateur", "password");

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top