visual studio insertar hacer editar datos creada consultas como buscar borrar .net sql-server security authentication runas

studio - ¿Cómo construir la funcionalidad RUNAS/NETONLY en un programa(C#/.NET/WinForms)?



como hacer consultas en visual studio 2012 (5)

Nuestras estaciones de trabajo no son miembros del dominio en el que se encuentra nuestro servidor SQL. (No están realmente en un dominio, no preguntes).

Cuando usamos SSMS o cualquier cosa para conectarnos al servidor SQL, usamos RUNAS / NETONLY con DOMINIO / usuario. Luego escribimos la contraseña y se inicia el programa. (RUNAS / NETONLY no le permite incluir la contraseña en el archivo por lotes).

Así que tengo una aplicación .NET WinForms que necesita una conexión SQL, y los usuarios tienen que iniciarla ejecutando un archivo por lotes que tenga la línea de comandos RUNAS / NETONLY y luego inicie el archivo EXE.

Si el usuario inicia el EXE de forma accidental, no puede conectarse a SQL Server.

Hacer clic con el botón derecho en la aplicación y usar la opción "Ejecutar como ..." no funciona (probablemente porque la estación de trabajo realmente no conoce el dominio).

Estoy buscando una forma para que la aplicación realice la funcionalidad RUNAS / NETONLY internamente antes de que comience algo significativo.

Consulte este enlace para obtener una descripción de cómo funciona RUNAS / NETONLY: http://www.eggheadcafe.com/conversation.aspx?messageid=32443204&threadid=32442982

Estoy pensando que voy a tener que usar LOGON_NETCREDENTIALS_ONLY con CreateProcessWithLogonW


Acabo de hacer algo similar a esto usando un ImpersonationContext . Es muy intuitivo de usar y me ha funcionado perfectamente.

Para ejecutar como un usuario diferente, la sintaxis es:

using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) ) { // code that executes under the new context... }

Aquí está la clase:

namespace Tools { #region Using directives. // ---------------------------------------------------------------------- using System; using System.Security.Principal; using System.Runtime.InteropServices; using System.ComponentModel; // ---------------------------------------------------------------------- #endregion ///////////////////////////////////////////////////////////////////////// /// <summary> /// Impersonation of a user. Allows to execute code under another /// user context. /// Please note that the account that instantiates the Impersonator class /// needs to have the ''Act as part of operating system'' privilege set. /// </summary> /// <remarks> /// This class is based on the information in the Microsoft knowledge base /// article http://support.microsoft.com/default.aspx?scid=kb;en-us;Q306158 /// /// Encapsulate an instance into a using-directive like e.g.: /// /// ... /// using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) ) /// { /// ... /// [code that executes under the new context] /// ... /// } /// ... /// /// Please contact the author Uwe Keim (mailto:[email protected]) /// for questions regarding this class. /// </remarks> public class Impersonator : IDisposable { #region Public methods. // ------------------------------------------------------------------ /// <summary> /// Constructor. Starts the impersonation with the given credentials. /// Please note that the account that instantiates the Impersonator class /// needs to have the ''Act as part of operating system'' privilege set. /// </summary> /// <param name="userName">The name of the user to act as.</param> /// <param name="domainName">The domain name of the user to act as.</param> /// <param name="password">The password of the user to act as.</param> public Impersonator( string userName, string domainName, string password) { ImpersonateValidUser(userName, domainName, password); } // ------------------------------------------------------------------ #endregion #region IDisposable member. // ------------------------------------------------------------------ public void Dispose() { UndoImpersonation(); } // ------------------------------------------------------------------ #endregion #region P/Invoke. // ------------------------------------------------------------------ [DllImport("advapi32.dll", SetLastError = true)] private static extern int LogonUser( string lpszUserName, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern int DuplicateToken( IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool RevertToSelf(); [DllImport("kernel32.dll", CharSet = CharSet.Auto)] private static extern bool CloseHandle( IntPtr handle); private const int LOGON32_LOGON_INTERACTIVE = 2; private const int LOGON32_PROVIDER_DEFAULT = 0; // ------------------------------------------------------------------ #endregion #region Private member. // ------------------------------------------------------------------ /// <summary> /// Does the actual impersonation. /// </summary> /// <param name="userName">The name of the user to act as.</param> /// <param name="domainName">The domain name of the user to act as.</param> /// <param name="password">The password of the user to act as.</param> private void ImpersonateValidUser( string userName, string domain, string password) { WindowsIdentity tempWindowsIdentity = null; IntPtr token = IntPtr.Zero; IntPtr tokenDuplicate = IntPtr.Zero; try { if (RevertToSelf()) { if (LogonUser( userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token) != 0) { if (DuplicateToken(token, 2, ref tokenDuplicate) != 0) { tempWindowsIdentity = new WindowsIdentity(tokenDuplicate); impersonationContext = tempWindowsIdentity.Impersonate(); } else { throw new Win32Exception(Marshal.GetLastWin32Error()); } } else { throw new Win32Exception(Marshal.GetLastWin32Error()); } } else { throw new Win32Exception(Marshal.GetLastWin32Error()); } } finally { if (token != IntPtr.Zero) { CloseHandle(token); } if (tokenDuplicate != IntPtr.Zero) { CloseHandle(tokenDuplicate); } } } /// <summary> /// Reverts the impersonation. /// </summary> private void UndoImpersonation() { if (impersonationContext != null) { impersonationContext.Undo(); } } private WindowsImpersonationContext impersonationContext = null; // ------------------------------------------------------------------ #endregion } ///////////////////////////////////////////////////////////////////////// }


Este código es parte de una clase RunAs que usamos para iniciar un proceso externo con privilegios elevados. Al pasar el nulo para el nombre de usuario y la contraseña, aparecerán las advertencias de UAC estándar. Al pasar un valor para el nombre de usuario y la contraseña, puede iniciar la aplicación elevada sin el indicador de UAC.

public static Process Elevated( string process, string args, string username, string password, string workingDirectory ) { if( process == null || process.Length == 0 ) throw new ArgumentNullException( "process" ); process = Path.GetFullPath( process ); string domain = null; if( username != null ) username = GetUsername( username, out domain ); ProcessStartInfo info = new ProcessStartInfo(); info.UseShellExecute = false; info.Arguments = args; info.WorkingDirectory = workingDirectory ?? Path.GetDirectoryName( process ); info.FileName = process; info.Verb = "runas"; info.UserName = username; info.Domain = domain; info.LoadUserProfile = true; if( password != null ) { SecureString ss = new SecureString(); foreach( char c in password ) ss.AppendChar( c ); info.Password = ss; } return Process.Start( info ); } private static string GetUsername( string username, out string domain ) { SplitUserName( username, out username, out domain ); if( domain == null && username.IndexOf( ''@'' ) < 0 ) domain = Environment.GetEnvironmentVariable( "USERDOMAIN" ); return username; }


He recogido estos enlaces útiles:

http://www.developmentnow.com/g/36_2006_3_0_0_725350/Need-help-with-impersonation-please-.htm

http://blrchen.spaces.live.com/blog/cns!572204F8C4F8A77A!251.entry

http://geekswithblogs.net/khanna/archive/2005/02/09/22430.aspx

http://msmvps.com/blogs/martinzugec/archive/2008/06/03/use-runas-from-non-domain-computer.aspx

Resulta que tendré que usar LOGON_NETCREDENTIALS_ONLY con CreateProcessWithLogonW . Voy a ver si puedo hacer que el programa detecte si se ha iniciado de esa manera y, de no ser así, reúna las credenciales del dominio y se inicie. De esa manera solo habrá un EXE autogestionable.


Sé que este es un hilo viejo, pero fue muy útil. Tengo exactamente la misma situación que Cade Roux, ya que quería una funcionalidad de estilo netonly.

¡La respuesta de John Rasch funciona con una pequeña modificación!

Agregue la siguiente constante (alrededor de la línea 102 para la consistencia):

private const int LOGON32_LOGON_NEW_CREDENTIALS = 9;

Luego cambie la llamada a LogonUser para usar LOGON32_LOGON_NEW_CREDENTIALS lugar de LOGON32_LOGON_INTERACTIVE .

¡¡¡Es el único cambio que tuve que hacer para que esto funcione perfectamente !!! Gracias John y Cade !!!

Aquí está el código modificado en su totalidad para facilitar la copia / pegado:

namespace Tools { #region Using directives. // ---------------------------------------------------------------------- using System; using System.Security.Principal; using System.Runtime.InteropServices; using System.ComponentModel; // ---------------------------------------------------------------------- #endregion ///////////////////////////////////////////////////////////////////////// /// <summary> /// Impersonation of a user. Allows to execute code under another /// user context. /// Please note that the account that instantiates the Impersonator class /// needs to have the ''Act as part of operating system'' privilege set. /// </summary> /// <remarks> /// This class is based on the information in the Microsoft knowledge base /// article http://support.microsoft.com/default.aspx?scid=kb;en-us;Q306158 /// /// Encapsulate an instance into a using-directive like e.g.: /// /// ... /// using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) ) /// { /// ... /// [code that executes under the new context] /// ... /// } /// ... /// /// Please contact the author Uwe Keim (mailto:[email protected]) /// for questions regarding this class. /// </remarks> public class Impersonator : IDisposable { #region Public methods. // ------------------------------------------------------------------ /// <summary> /// Constructor. Starts the impersonation with the given credentials. /// Please note that the account that instantiates the Impersonator class /// needs to have the ''Act as part of operating system'' privilege set. /// </summary> /// <param name="userName">The name of the user to act as.</param> /// <param name="domainName">The domain name of the user to act as.</param> /// <param name="password">The password of the user to act as.</param> public Impersonator( string userName, string domainName, string password) { ImpersonateValidUser(userName, domainName, password); } // ------------------------------------------------------------------ #endregion #region IDisposable member. // ------------------------------------------------------------------ public void Dispose() { UndoImpersonation(); } // ------------------------------------------------------------------ #endregion #region P/Invoke. // ------------------------------------------------------------------ [DllImport("advapi32.dll", SetLastError = true)] private static extern int LogonUser( string lpszUserName, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern int DuplicateToken( IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool RevertToSelf(); [DllImport("kernel32.dll", CharSet = CharSet.Auto)] private static extern bool CloseHandle( IntPtr handle); private const int LOGON32_LOGON_INTERACTIVE = 2; private const int LOGON32_LOGON_NEW_CREDENTIALS = 9; private const int LOGON32_PROVIDER_DEFAULT = 0; // ------------------------------------------------------------------ #endregion #region Private member. // ------------------------------------------------------------------ /// <summary> /// Does the actual impersonation. /// </summary> /// <param name="userName">The name of the user to act as.</param> /// <param name="domainName">The domain name of the user to act as.</param> /// <param name="password">The password of the user to act as.</param> private void ImpersonateValidUser( string userName, string domain, string password) { WindowsIdentity tempWindowsIdentity = null; IntPtr token = IntPtr.Zero; IntPtr tokenDuplicate = IntPtr.Zero; try { if (RevertToSelf()) { if (LogonUser( userName, domain, password, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, ref token) != 0) { if (DuplicateToken(token, 2, ref tokenDuplicate) != 0) { tempWindowsIdentity = new WindowsIdentity(tokenDuplicate); impersonationContext = tempWindowsIdentity.Impersonate(); } else { throw new Win32Exception(Marshal.GetLastWin32Error()); } } else { throw new Win32Exception(Marshal.GetLastWin32Error()); } } else { throw new Win32Exception(Marshal.GetLastWin32Error()); } } finally { if (token != IntPtr.Zero) { CloseHandle(token); } if (tokenDuplicate != IntPtr.Zero) { CloseHandle(tokenDuplicate); } } } /// <summary> /// Reverts the impersonation. /// </summary> private void UndoImpersonation() { if (impersonationContext != null) { impersonationContext.Undo(); } } private WindowsImpersonationContext impersonationContext = null; // ------------------------------------------------------------------ #endregion } ///////////////////////////////////////////////////////////////////////// }


Supongo que no puede simplemente agregar un usuario para la aplicación al servidor de SQL y luego usar la autenticación de SQL en lugar de la autenticación de Windows.