G
Guest
Hi,
I have a .NET WinForms application that needs to identify the user and
authenticate this against a datastore (could be Access, SQL Server, or
Oracle). Currently, our login process is forms based so whatever login the
user enters, together with the password, are matched against a table in the
datastore to determine what level of access they should receive.
We now want to support Windows Integrated auth so that the user does not
have to enter a login name and password. One way to do this is to identify
the user based on their domain\username. However, this can be spoofed, by
setting up another computer so that the application is run under the same
domain\username and then connecting to the datastore (since the user doesn't
actually have to login to the domain in order to access the datastore, e.g.
Access file on local drive or when connecting to SQL Server via TCP/IP).
The one solution I've come up with is to store the user's SID instead of
domain\username, since according to the article at
http://www.microsoft.com/resources/...03/standard/proddocs/en-us/sag_ADintro_12.asp
this is guaranteed to be unique and is in fact the method Windows uses to
refer to user accounts.
Is my assessment of how to implement Windows Integrated auth correct?
I have even written a short C# application that retrieves the SID for a user
account (I include the source below).
using System;
using System.Text;
using System.Diagnostics;
using System.DirectoryServices;
namespace GetWindowsAuthName
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Application
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
PrintUsageInstructions();
System.Security.Principal.WindowsIdentity identity =
System.Security.Principal.WindowsIdentity.GetCurrent();
string username;
if (args.Length > 0)
{
username = args[0];
}
else
{
username = identity.Name;
}
PrintSidInformation(username);
Console.WriteLine();
Console.Write("Press <ENTER> to continue...");
Console.ReadLine();
}
private static void PrintSidInformation(string username)
{
Console.WriteLine("Getting SID for: " + username);
Console.WriteLine("SID = " + GetSid(username));
}
private static void PrintUsageInstructions()
{
Console.WriteLine("Usage instructions:");
Console.WriteLine(@"GetWinAuthDetails [username@domain] [domain\username]");
Console.WriteLine();
}
private static string GetSid(string strLogin)
{
string str = "";
// Parse the string to check if domain name is present.
int idx = strLogin.IndexOf('\\');
if (idx == -1)
{
idx = strLogin.IndexOf('@');
}
string strDomain;
string strName;
if (idx != -1)
{
strDomain = strLogin.Substring(0, idx);
strName = strLogin.Substring(idx+1);
}
else
{
strDomain = Environment.MachineName;
strName = strLogin;
}
Debug.WriteLine("Domain: " + strDomain);
Debug.WriteLine("Username: " + strName);
DirectoryEntry obDirEntry = null;
try
{
Int64 iBigVal = 5;
Byte[] bigArr = BitConverter.GetBytes(iBigVal);
obDirEntry = new DirectoryEntry("WinNT://" + strDomain + "/" + strName);
System.DirectoryServices.PropertyCollection coll = obDirEntry.Properties;
object obVal = coll["objectSid"].Value;
if (null != obVal)
{
str = ConvertByteToStringSid((Byte[])obVal);
}
}
catch (Exception ex)
{
str = "";
Debug.Write(ex.Message);
}
return str;
}
private static string ConvertByteToStringSid(Byte[] sidBytes)
{
short sSubAuthorityCount = 0;
StringBuilder strSid = new StringBuilder();
strSid.Append("S-");
try
{
// Add SID revision.
strSid.Append(sidBytes[0].ToString());
sSubAuthorityCount = Convert.ToInt16(sidBytes[1]);
// Next six bytes are SID authority value.
if (sidBytes[2] != 0 || sidBytes[3] != 0)
{
string strAuth = String.Format("0x{0:2x}{1:2x}{2:2x}{3:2x}{4:2x}{5:2x}",
(Int16)sidBytes[2],
(Int16)sidBytes[3],
(Int16)sidBytes[4],
(Int16)sidBytes[5],
(Int16)sidBytes[6],
(Int16)sidBytes[7]);
strSid.Append("-");
strSid.Append(strAuth);
}
else
{
Int64 iVal = (Int32)(sidBytes[7]) +
(Int32)(sidBytes[6] << 8) +
(Int32)(sidBytes[5] << 16) +
(Int32)(sidBytes[4] << 24);
strSid.Append("-");
strSid.Append(iVal.ToString());
}
// Get sub authority count...
int idxAuth = 0;
for (int i = 0; i < sSubAuthorityCount; i++)
{
idxAuth = 8 + i * 4;
UInt32 iSubAuth = BitConverter.ToUInt32(sidBytes, idxAuth);
strSid.Append("-");
strSid.Append(iSubAuth.ToString());
}
}
catch (Exception ex)
{
Trace.WriteLine(ex.Message);
return "";
}
return strSid.ToString();
}
}
}
I have a .NET WinForms application that needs to identify the user and
authenticate this against a datastore (could be Access, SQL Server, or
Oracle). Currently, our login process is forms based so whatever login the
user enters, together with the password, are matched against a table in the
datastore to determine what level of access they should receive.
We now want to support Windows Integrated auth so that the user does not
have to enter a login name and password. One way to do this is to identify
the user based on their domain\username. However, this can be spoofed, by
setting up another computer so that the application is run under the same
domain\username and then connecting to the datastore (since the user doesn't
actually have to login to the domain in order to access the datastore, e.g.
Access file on local drive or when connecting to SQL Server via TCP/IP).
The one solution I've come up with is to store the user's SID instead of
domain\username, since according to the article at
http://www.microsoft.com/resources/...03/standard/proddocs/en-us/sag_ADintro_12.asp
this is guaranteed to be unique and is in fact the method Windows uses to
refer to user accounts.
Is my assessment of how to implement Windows Integrated auth correct?
I have even written a short C# application that retrieves the SID for a user
account (I include the source below).
using System;
using System.Text;
using System.Diagnostics;
using System.DirectoryServices;
namespace GetWindowsAuthName
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Application
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
PrintUsageInstructions();
System.Security.Principal.WindowsIdentity identity =
System.Security.Principal.WindowsIdentity.GetCurrent();
string username;
if (args.Length > 0)
{
username = args[0];
}
else
{
username = identity.Name;
}
PrintSidInformation(username);
Console.WriteLine();
Console.Write("Press <ENTER> to continue...");
Console.ReadLine();
}
private static void PrintSidInformation(string username)
{
Console.WriteLine("Getting SID for: " + username);
Console.WriteLine("SID = " + GetSid(username));
}
private static void PrintUsageInstructions()
{
Console.WriteLine("Usage instructions:");
Console.WriteLine(@"GetWinAuthDetails [username@domain] [domain\username]");
Console.WriteLine();
}
private static string GetSid(string strLogin)
{
string str = "";
// Parse the string to check if domain name is present.
int idx = strLogin.IndexOf('\\');
if (idx == -1)
{
idx = strLogin.IndexOf('@');
}
string strDomain;
string strName;
if (idx != -1)
{
strDomain = strLogin.Substring(0, idx);
strName = strLogin.Substring(idx+1);
}
else
{
strDomain = Environment.MachineName;
strName = strLogin;
}
Debug.WriteLine("Domain: " + strDomain);
Debug.WriteLine("Username: " + strName);
DirectoryEntry obDirEntry = null;
try
{
Int64 iBigVal = 5;
Byte[] bigArr = BitConverter.GetBytes(iBigVal);
obDirEntry = new DirectoryEntry("WinNT://" + strDomain + "/" + strName);
System.DirectoryServices.PropertyCollection coll = obDirEntry.Properties;
object obVal = coll["objectSid"].Value;
if (null != obVal)
{
str = ConvertByteToStringSid((Byte[])obVal);
}
}
catch (Exception ex)
{
str = "";
Debug.Write(ex.Message);
}
return str;
}
private static string ConvertByteToStringSid(Byte[] sidBytes)
{
short sSubAuthorityCount = 0;
StringBuilder strSid = new StringBuilder();
strSid.Append("S-");
try
{
// Add SID revision.
strSid.Append(sidBytes[0].ToString());
sSubAuthorityCount = Convert.ToInt16(sidBytes[1]);
// Next six bytes are SID authority value.
if (sidBytes[2] != 0 || sidBytes[3] != 0)
{
string strAuth = String.Format("0x{0:2x}{1:2x}{2:2x}{3:2x}{4:2x}{5:2x}",
(Int16)sidBytes[2],
(Int16)sidBytes[3],
(Int16)sidBytes[4],
(Int16)sidBytes[5],
(Int16)sidBytes[6],
(Int16)sidBytes[7]);
strSid.Append("-");
strSid.Append(strAuth);
}
else
{
Int64 iVal = (Int32)(sidBytes[7]) +
(Int32)(sidBytes[6] << 8) +
(Int32)(sidBytes[5] << 16) +
(Int32)(sidBytes[4] << 24);
strSid.Append("-");
strSid.Append(iVal.ToString());
}
// Get sub authority count...
int idxAuth = 0;
for (int i = 0; i < sSubAuthorityCount; i++)
{
idxAuth = 8 + i * 4;
UInt32 iSubAuth = BitConverter.ToUInt32(sidBytes, idxAuth);
strSid.Append("-");
strSid.Append(iSubAuth.ToString());
}
}
catch (Exception ex)
{
Trace.WriteLine(ex.Message);
return "";
}
return strSid.ToString();
}
}
}