Pregunta

Me hizo una pregunta hace unos días ( Acceso a SQL Server 2005 desde una máquina no es de dominio mediante la autenticación de Windows ), que tiene algo interesante, pero no utilizables sugerencias. Me gustaría hacer la pregunta de nuevo, pero dejar claro cuáles son mis limitaciones son:

Tengo un dominio de Windows en el que una máquina se está ejecutando SQL Server 2005 y el cual está configurado para admitir sólo la autenticación de Windows. Me gustaría correr una aplicación cliente de C # en una máquina en la misma red, pero que no está en el dominio, y el acceso a una base de datos en la instancia de SQL Server 2005.

No se puede crear o modificar usuarios del sistema operativo o de SQL Server en cualquiera de las máquinas, y no puedo realizar ningún cambio en los permisos o la suplantación, y no puedo hacer uso de runas.

Yo sé que puedo escribir aplicaciones Perl y Java que pueden conectarse a la base de datos de SQL Server utilizando sólo estos cuatro parámetros:. Nombre del servidor, nombre de la base de datos, nombre de usuario (en el formato dominio \ usuario) y contraseña

En C # He intentado varias cosas:

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

e intentado fijar la seguridad integrada de verdadero y falso, pero nada parece funcionar. Es lo que estoy tratando de hacer simplemente imposible en C #?

Gracias por cualquier ayuda, Martin

¿Fue útil?

Solución

Como se dice correctamente, JDBC o Perl en una máquina Linux puede conectar tanto a un servidor SQL utilizando la autenticación de Windows y credenciales que se diferencian del usuario actualmente conectado. Lo mismo es cierto para los dispositivos de Windows CE , por cierto.

creo que esto es que esto no es una cuestión de C #, sino del controlador de SQL Server OLE DB. Creo que los métodos mencionados anteriormente "pretendo ser una máquina Windows usando unas credenciales específicas" en el nivel de la red; una característica, que carece del controlador de SQL Server OLE DB. Por lo tanto, mi sugerencia sería la de buscar una alternativa (quizá comercial?) Controlador OLE DB que las bases de datos de acceso puede SQL Server. No estoy seguro de si existe tal cosa, sin embargo.

Otros consejos

He tenido un problema similar en el que estaba escribiendo una herramienta que necesita para funcionar en una máquina en un dominio y autenticar con un servidor SQL en otro dominio utilizando una conexión de confianza. Todo lo que pude encontrar sobre el tema dijo que no se podía hacer. En lugar de ello debe unirse al dominio, el uso de la autenticación de SQL, esta actividad que muchacho llamado Kerberos, o recuperar su individuos de la red para configurar una relación de confianza, por nombrar algunas alternativas.

Lo que pasa es que sabía que podía conseguir que funcione de alguna manera el uso de RUNAS porque había demostrado 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"

La bandera / netonly me ha permitido para ejecutar el exe con las credenciales locales y el acceso a la red con las credenciales remotas, creo, de todos modos me dieron el conjunto de resultados que esperaba desde el servidor remoto. El problema fue el comando de runa hace que sea muy difícil para depurar la aplicación, y no olía bien.

Con el tiempo me encontré con este artículo sobre el proyecto de código que fue hablando de autenticación para manipular Active Directory, aquí es la clase principal que realiza la suplantación:

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

Para usarlo simplemente:

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

//Connect to and use SQL server

impersonator.Undo();

I añadido en el método Deshacer lo contrario el objeto imitador tendía a estar basura recogida. También alteré el código para LOGON32_LOGON_NEW_CREDENTIALS uso, pero esto fue un golpe y correr para que funcione; Todavía necesito para entender completamente lo que hace, tengo la sensación es la misma que el / la bandera netonly en runas. También voy a romper el constructor un poco.

Es inútil para especificar el nombre de usuario y contraseña en la cadena de conexión, porque los implica la autenticación de SQL, y ya se especifica que SQL Server sólo acepta la autenticación de Windows.

Si el servidor no permite la autenticación de SQL entonces el Sólo Posibilidad de conexión es utilizar la autenticación de Windows, es decir. IntegratedSecurity=true. Lo que significa que su cliente va a autenticar credenciales como lo está en marcha el proceso (o está siendo suplantado).

Para que la autenticación de Windows para el trabajo, usted tiene que elegir uno de los siguientes:

  • Únete a la no-dominio unido a máquina en un dominio (que puede ser su propio dominio!) Que confía en el dominio del servidor, a continuación, ejecute el proceso de cliente como un dominio \ credencial de usuario.
  • Uso de NTLM refleja cuentas: un par de usuarios locales en el cliente y el servidor con el nombre y contraseñas idénticos
  • .
  • Grant como el acceso anónimo al servidor SQL.

Si no puede hacer que la máquina cliente la confianza del dominio del servidor, ni se puede añadir NTLM refleja cuentas, y el administrador de SQL Server es lo suficientemente cuerdo para no permitir ANÓNIMO, entonces no será capaz de conectarse.

Hay que de configuración de SQL Server para permitir la autenticación de SQL Server , es decir, la autenticación mediante nombre de usuario y contraseña.

No se puede autenticar por dominio nombre de usuario / contraseña 'como' autenticación del servidor, es decir, especificar nombre de usuario de dominio / contraseña directamente.

I puede estar equivocado, por supuesto, pero estoy seguro de que esto no es un problema de C # o .NET. ¿Cómo se puede iniciar sesión en SQL Server en su aplicación Perl o Java ??

Te voy a dar la respuesta de Java, que estoy más familiarizado con: Yo uso el controlador JDBC jTDS con los cuatro parámetros mencionados anteriormente. La aplicación Perl sé menos aproximadamente, pero se está ejecutando en una máquina Linux, y es capaz de conectar con los mismos parámetros. No puedo cambiar el servidor SQL Server para soportar la autenticación de SQL.

Para responder a sugerencias de Remus, no puedo hacer ninguna de esas tres cosas que él sugiere y aplicaciones Java y Perl todavía son capaces de conectarse. Alguna otra idea?

Gracias, Martin

¿Es una opción de mensaje de credenciales ?

Aquí está el código de ejemplo que utilizo para conectar desde una máquina no es de dominio utilizando el controlador JDBC jTDS:

Class.forName ( "net.sourceforge.jtds.jdbc.Driver") newInstance ().; String url = "jdbc: sqlserver: jtds: // servidor / base de datos; domain = Dominio"; conn = DriverManager.getConnection (url, "usuario", "contraseña");

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top