Skip to content

Instantly share code, notes, and snippets.

@justincjahn
Created February 2, 2012 23:45
Show Gist options
  • Save justincjahn/1726488 to your computer and use it in GitHub Desktop.
Save justincjahn/1726488 to your computer and use it in GitHub Desktop.
AD Authentication
<%@ Import Namespace="System" %>
<%@ Import Namespace="System.Text.RegularExpressions" %>
<%@ Import Namespace="System.DirectoryServices" %>
<%@ Import Namespace="System.Web" %>
<%@ Page Language="C#" %>
<script language="c#" runat="server">
// Constants
const string AD_SERVER = "10.0.0.0";
const string AD_DOMAIN = "AD";
// A list of possible errors with the login form.
Dictionary<String, String> aErrors = new Dictionary<string,string>();
// The return values of the authentication request, if done.
bool IsAuthenticated = false;
SearchResult oResult;
string[] aGroups;
/// <summary>
/// Occurs when the page loads.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void Page_Load(object sender, EventArgs e)
{
if (Page.IsPostBack) {
// Initialize variables
String sUsername = Request.Form["username"].Trim();
String sPassword = Request.Form["password"];
// Validate username characters
Regex oReg = new Regex(@"^[a-zA-Z0-9]{3,}$");
if (!oReg.IsMatch(sUsername))
{
// Add an error to the hashtable
aErrors["username"] = "Username contains invalid characters or is too short.";
}
// Validate password length
if (sPassword.Length < 6) {
aErrors["password"] = "Password is too short.";
}
// Check to see if we're clear to send the information to AD
if (aErrors.Count == 0) {
try {
// Attempt the login
oResult = Login(sUsername, sPassword);
aGroups = Groups(oResult).ToArray();
IsAuthenticated = true;
} catch (Exception error) {
aErrors["failure"] = "Username or password not found: " + error.Message;
}
}
}
}
/// <summary>
/// Validate a user's credentials via AD.
/// </summary>
/// <param name="username">The users identity.</param>
/// <param name="password">The user's credential.</param>
/// <exception cref="Exception">If the connection to AD fails.</exception>
/// <returns>The user's path in Active Directory.</returns>
protected SearchResult Login(string username, string password)
{
// Create the full username from provided username
string sDomainUser = AD_DOMAIN + @"\" + username;
// Create the DirectoryEntry we will use to query AD
DirectoryEntry oEntry = new DirectoryEntry(@"LDAP://" + AD_SERVER, sDomainUser, password);
// If the connection to the server fails or the user isn't valid an
// exception will be thrown.
try {
// Force authentication by binding the native object
object oNative = oEntry.NativeObject;
// Query the user's information
DirectorySearcher oSearch = new DirectorySearcher(oEntry);
oSearch.Filter = "(SAMAccountName=" + username + ")";
// Add items to return as a result
oSearch.PropertiesToLoad.Add("cn");
oSearch.PropertiesToLoad.Add("memberOf");
// Do the query
SearchResult oResult = oSearch.FindOne();
// Determine if the user is valid
if (oResult == null) {
// It isn't, so return an empty string
throw new Exception("Username or Password not found.");
} else {
// It is, return the path to the user within AD
return oResult;
}
} catch (Exception e) {
// Something went wrong, throw an exception
throw new Exception("Unable to authenticate user: " + e.Message);
}
}
/// <summary>
/// Fetch the groups for a specific user.
/// </summary>
/// <param name="result">The result of an AD/LDAP query.</param>
/// <returns>A list of groups.</returns>
public List<string> Groups(SearchResult result)
{
// Verify the result has a memberOf property
if (!result.Properties.Contains("memberOf")) {
throw new Exception("No group information provided with result.");
}
// Create the StringBuilder that will gather the groups together
List<string> oGroups = new List<string>();
try {
// Loop through each returned memberOf entry and format it properly
int iCount = result.Properties["memberOf"].Count;
int iEquals, iComma;
string dn;
for (int i = 0; i < iCount; i++) {
// Get the LDAP DN of the entry
dn = (string)result.Properties["memberOf"][i];
// Find the location of the equal sign and comman within the DN
iEquals = dn.IndexOf("=", 1);
iComma = dn.IndexOf(",", 1);
// If we don't have an equal sign then we don't have any groups
if (iEquals == -1) return oGroups;
// Add the substring (and resulting group) to our StringBuilder object
oGroups.Add(dn.Substring((iEquals + 1), (iComma - iEquals) - 1));
}
} catch (Exception e) {
throw new Exception("Error obtaining groups names: " + e.Message);
}
// Return the group names
return oGroups;
}
</script>
<!DOCTYPE html>
<html>
<head>
<title>Hello, World!</title>
</head>
<body>
<h1>Please Login</h1>
<% if (IsAuthenticated == true) { %>
<h2>Login Success!</h2>
<p class="success">
<%=oResult.Path%>
</p>
<p class="success">
<%=String.Join(", ", aGroups)%>
</p>
<% } %>
<% if (aErrors.ContainsKey("failure")) { %>
<h2>Login Failure!</h2>
<p class="error"><%=aErrors["failure"]%></p>
<% } %>
<form action="Default.aspx" method="post" runat="server">
<dl class="login">
<dt><label for="username">Username</label></dt>
<dd><input type="text" name="username" id="username" /></dd>
<% if (aErrors.ContainsKey("username")) { %>
<dd><p class="error"><%=aErrors["username"]%></p></dd>
<% } %>
<dt><label for="password">Password</label></dt>
<dd><input type="password" name="password" id="password" /></dd>
<% if (aErrors.ContainsKey("password")) { %>
<dd><p class="error"><%=aErrors["password"]%></p></dd>
<% } %>
<dt>&nbsp;</dt>
<dd><input type="submit" name="loginSubmit" id="loginSubmit" value="Login" /></dd>
</dl>
</form>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment