Hello all,
My first post to the board and it's going to be a "I'm having trouble with my authentication code..." *lol* I was so determined to work it out myself too.
Ok, Through reading various posts & sites I've cobbled together a couple of pages to perform forms based authentication.
It all seems to work and I authenticate fine, however it doesn't seem to be passing the roles so that I can use User.IsInRole().
I'm writing the ticket and setting up the General Principal and there are no errors, but the bit of code I put in my index page to test if I could read the roles is coming back false.
Anyway, here's the code, please excuse the cludgyness, but my copy of VS.NET isn't here yet so this is all done using good old fashioned notepad.
web.config:
<CODE>
<configuration>
<system.web>
<customErrors mode="Off"/>
<authentication mode="Forms">
<forms name="./IMOECookie" loginUrl="login.aspx" protection="All" timeout="1" path="/"/>
</authentication>
<authorization>
<deny users="?" />
</authorization>
<identity impersonate="true" />
</system.web>
</configuration>
</CODE>
Login.aspx
<CODE>
<%... Import Namespace="System.DirectoryServices" %>
<%... Import Namespace="System.Security.Principal" %>
<html>
<script language="C#" runat=server>
string LDAPPATH = "LDAP://hundredacrewood.local/DC=hundredacrewood,DC=local";
string _filterAttribute = "";
int CookieTimeOut = 1;
public bool AuthenticateUser(string domain, string username, string password)
{
string domainAndUsername = domain + ..."\" + username;
DirectoryEntry entry = new DirectoryEntry( LDAPPATH, domainAndUsername, password);
try
{
// Bind to the native AdsObject to force authentication.
Object obj = entry.NativeObject;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");
SearchResult result = search.FindOne();
if(null == result)
{
return false;
}
// Update the new path to the user in the directory
LDAPPATH = result.Path;
_filterAttribute = (String)result.Properties["cn"][0];
}
catch (Exception ex)
{
lblResults.Text = "Error: " + ex.Message;
return false;
}
lblResults.Text = "";
return true;
}
void LoadUser(string username)
{
DirectorySearcher search = new DirectorySearcher(LDAPPATH);
search.Filter = "(cn=" + _filterAttribute + ")";
search.PropertiesToLoad.Add("memberOf");
StringBuilder groupNames = new StringBuilder();
try
{
SearchResult result = search.FindOne();
int propertyCount = result.Properties["memberOf"].Count;
String dn;
int equalsIndex, commaIndex;
for(int propertyCounter = 0; propertyCounter < propertyCount; propertyCounter++)
{
dn = (String)result.Properties["memberOf"][propertyCounter];
equalsIndex = dn.IndexOf("=", 1);
commaIndex = dn.IndexOf(",", 1);
groupNames.Append(dn.Substring((equalsIndex + 1), (commaIndex - equalsIndex) - 1));
groupNames.Append("|");
}
}
catch(Exception ex)
{
lblResults.Text = "Error: " + ex.Message;
}
lblResults.Text = "";
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1, username, DateTime.Now, DateTime.Now.AddMinutes(CookieTimeOut), false,groupNames.ToString(), "/");
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
HttpCookie authCookie = new HttpCookie( FormsAuthentication.FormsCookieName , encryptedTicket);
Response.Cookies.Add(authCookie);
}
void Login_Click(Object sender, EventArgs E)
{
if(AuthenticateUser(UserDomain.Value, UserName.Value, UserPass.Value))
{
LoadUser(UserName.Value);
Response.Redirect(FormsAuthentication.GetRedirectUrl(UserDomain.Value,false));
}
}
</script>
<body>
<form runat="server" ID="Form1">
<h3>Login Page</h3>
<hr>
UserName:<input id="UserName" type="text" runat="server"/>
<asp:RequiredFieldValidator ControlToValidate="UserName" Display="Static" ErrorMessage="*" runat="server"/>
<P>
Password:<input id="UserPass" type="password" runat="server"/>
<asp:RequiredFieldValidator ControlToValidate="UserPass" Display="Static" ErrorMessage="*" runat="server"/>
</P>
<P>
Domain:<input id="UserDomain" type="text" runat="server"/>
<asp:RequiredFieldValidator ControlToValidate="UserDomain" Display="Static" ErrorMessage="*" runat="server"/>
</P>
<P>
<asp:button id="cmdLogin" text="Login" OnClick="Login_Click" runat="server"/>
</P>
<P>
<asp:Label id="lblResults" ForeColor="red" Font-Size="10" runat="server" />
</P>
</form>
</body>
</html>
</CODE>
Global.axas
<CODE>
<%... Application Codebehind="Global.asax.cs"%>
</CODE>
Snippet from Global.axas.cs
<CODE>
void Application_AuthenticateRequest(Object sender, EventArgs e)
{
String cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
if(null == authCookie)
{//There is no authentication cookie.
return;
}
FormsAuthenticationTicket authTicket = null;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch(Exception ex)
{
//Write the exception to the Event Log.
return;
}
if(null == authTicket)
{//Cookie failed to decrypt.
return;
}
//When the ticket was created, the UserData property was assigned a
//pipe-delimited string of group names.
String[] groups = authTicket.UserData.Split(new char[]{'|'});
//Create an Identity.
GenericIdentity id = new GenericIdentity(authTicket.Name, "LdapAuthentication");
//This principal flows throughout the request.
GenericPrincipal principal = new GenericPrincipal(id, groups);
Context.User = principal;
}
</CODE>
index.aspx (Yes I know I switched to VB.NET :) )
<CODE>
<script runat="server">
sub Page_Load
if Not Page.IsPostBack then
dim mycountries=New Hashtable
mycountries.Add("N","Norway")
mycountries.Add("S","Sweden")
mycountries.Add("F","France")
mycountries.Add("I","Italy")
rb.DataSource=mycountries
rb.DataValueField="Key"
rb.DataTextField="Value"
rb.DataBind()
end if
end sub
sub displayMessage(s as Object,e As EventArgs)
lbl1.text="Your favorite country is: " & rb.SelectedItem.Text
if User.IsInRole("Test") then
lbl2.text = "Test"
else
lbl2.text = "Not Test"
end if
end sub
</script><html>
<body><form runat="server">
<asp:RadioButtonList id="rb" runat="server"
AutoPostBack="True" onSelectedIndexChanged="displayMessage" />
<p><asp:label id="lbl1" runat="server" /></p>
<p><asp:label id="lbl2" runat="server" /></p>
</form></body>
</html>
</CODE>
A fair bit of cut and paste code, and the global.asax.cs was taken piecemeal from this site. But still not bad considering that I've never touched .NET or C# before and I've no books, or dev tools here (unless you count Notepad) :)
So, if anyone can help me crack the roles issue I'd be very grateful.