DotNet Security: Yet another newbie need to ask about Authentication Code... :)

  • jennih / 102 / Tues, 19 Jan 2010 10:04:00 GMT / Comments (3)
  • 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.

  • Keywords:

    newbie, ask, authentication, code, dotnet, security, .net

  • http://dotnet.itags.org/dotnet-security/37911/«« Last Thread - Next Thread »»

    1. Jenni

      Can you try doing 2 things


      1. Put this Code at the end of the Application_AuthenticateRequest(..)To See the List of Groups the Authenticated User is a Member Of
      Response.Write ( "Groups: " + authTicket.UserData + "<br>");

      2. make sure that the DomainName is a Valid One ( means tha the"Test" is a Valid Role or it exists in the groups array)

      see how it works

      luvdotnet | Tues, 01 Jan 2008 02:29:00 GMT |

    2. Ok, I added the line with no success, so at the begining of AuthenticateRequest I put a simple Response.Write ("Got Here") to see if the section of code ran at all, but nothing.

      So, I double checked the Security Group, and it was fine and added a line of code to display the contents of the variable before it's loaded into the cookie and it's as I expected A list of Groups separated by vertical bars and Test was one of them.

      The problem has to either be:
      A) The value isn'r being correctly loaded into the Cookie

      Or my personal belief,

      B) The AuthenticateRequest code isn't running at all or is running incorrectly.

      jennih | Tues, 01 Jan 2008 02:30:00 GMT |


    3. i am not sure if this is the problem but worth trying it

      1 .You are creating the FormsAuthenticationTicket with theUserName thatwill be associated with the Ticket , which is right

      FormsAuthenticationTicket authTicket = newFormsAuthenticationTicket(1, username, DateTime.Now,DateTime.Now.AddMinutes(CookieTimeOut), false,groupNames.ToString(),"/")

      but when redirecting you are the UserDomain.Value when ( or tofire the Application_AuthenticateRequest ) can you please changeit to user UserName instead and see if it works


      2. And also you said that you put some line of code Response.Write("Got Here") and its not hitting that means the AuthenticateRequestevent is not fired which means that The AuthenticatedUser is returningfalse or the User is not Authenticated can you please check on that aswell

      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));// THIS SHOULD FIRE APPLICATION_AUTHENTICATEREQUEST Event , which meansthe User has to be authenticated first in ur code
      }
      }


      3 .Also try adding the <allow users = "*' /> tag as well in theauthorization tag in the config ( this should not matter but worhgivign a try )

      hth
      Vivek








      luvdotnet | Tues, 01 Jan 2008 02:31:00 GMT |