DotNetNuke : A Single Sign on Solution (C#)

DotNetNuke is an ideal place to to use as a starting point for all of your users. Frequently users need to access external applications and they are required to log into those applications again after logging into DotNetNuke. A more desired solution would be to have the users automatically logged into the external application after logging into DotNetNuke. This is known as "Single Sign On".

But how to achieve this? One solution is to use shared forms authentication. This works but has it's limitations. This article explains the various ways it can be used.  The main limitation is that a complex structure of shared cookies and redirects is required when the DotNetNuke site and the external application are located in different domains.

The goal of this exercise is to create a "Single Sign On" solution that works with any domain configuration, any web browser and is secure and reliable.

The Single Sign On Solution

The solution is outlined in these steps:

  1. The user logs onto the DotNetNuke site.

  2. The DotNetNuke site makes a web service call to the external application and instructs the external application to create a temporary password for the user in it's database. The DotNetNuke site then creates a link to the external application with the username and temporary password as parameters.

  3. The user clicks on the link navigating to the external application. The external application receives the call, and after verifying the temporary password, creates an authentication token and automatically logs the user in. The external application then replaces the temporary password in it's database with a new random one. 

Create the External Application

In Visual Studio 2005 or Visual Web Developer Express create a web application that uses Forms Authentication.

If the website is a file based website, in Visual Studio, you can select Website then ASP.NET Configuration to configure a directory that is not accessible by unauthenticated users. Otherwise, you can edit the web.config file manually (see the code at the end of this article).

 

In this example the directory Secure is configured to not allow unauthenticated users. 

 

Next, a table is created that holds the temporary username and password:

 

(This table cannot be the table that is used to store the normal username and password for the application.)

Next a web service is created that will allow the DotNetNuke site to create a temporary password for a user:

public bool SetAuthendication(string tmpMasterPassword, String username, string password) 
    {
        bool isSuccess = false;
        string MasterPassword;
        string strSQL = "";
        MasterPassword = WebConfigurationManager.AppSettings["MasterPassword"];
 
        if (tmpMasterPassword == MasterPassword)
        {
            bool boolUserExists = UserExists(username);
 
            if (boolUserExists)
            {
                strSQL = "Update SingleSignOnUsers set password = @password where username = @username";
            }
            else
            {
                strSQL = "Insert into SingleSignOnUsers ([username],[password]) values (@username, @password) ";
            }
 
            SqlCommand cmd = new SqlCommand(strSQL, new SqlConnection(GetConnectionString()));
            cmd.CommandType = CommandType.Text;
 
            cmd.Parameters.Add(new SqlParameter("@password", password));
            cmd.Parameters.Add(new SqlParameter("@username", username));
 
            cmd.Connection.Open();
            cmd.ExecuteNonQuery();
            cmd.Connection.Close();
            
            isSuccess = true;
        }
 
        return isSuccess;
    }

(For added security the web service method should be called using SSL (secure socket layer))

Next, a page is created that will receive a username and password. If it finds the user in the table, it will log the user in:

protected void Page_Load(object sender, EventArgs e)
    {
        string username = Request.QueryString["username"].ToString();
        string password = Request.QueryString["password"].ToString();
 
 
        if (ISAuthendicated(username, password))
        {
            lblStatus.Text = "Authendication Success";
            FormsAuthenticationTicket fat = new FormsAuthenticationTicket(1, username, DateTime.Now, DateTime.Now.AddYears(1), true, "");
            HttpCookie cookie = new HttpCookie(".SingleSignOn");
            cookie.Value = FormsAuthentication.Encrypt(fat);
            cookie.Expires = fat.Expiration;
            HttpContext.Current.Response.Cookies.Add(cookie);
        }
        else
        {
            hlLoggedin.Visible = false;
            lblStatus.Text = "Authendication Failed";
        }
 
        //Reset the password
        //Even a failed attempt will cause a new password to be created
        //A hacker would be chasing a moving target
        DeletePassword(username);
 
    }
 
    private bool ISAuthendicated(string username, string password)
    {
        string tmpPassword = "";
        string strSQL = "Select password from SingleSignOnUsers where [username] = @username";
 
        SqlCommand cmd = new SqlCommand(strSQL, new SqlConnection(GetConnectionString()));
        cmd.CommandType = CommandType.Text;
        cmd.Parameters.Add(new SqlParameter("username", username));
        cmd.Connection.Open();
 
        SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
        while (dr.Read())
        {
            tmpPassword = Convert.ToString(dr["password"]);
        }
 
        dr.Close();
 
        return (tmpPassword == password & password != "");
    }
 
    private void DeletePassword(String username)
    {
        Random rnd = new Random();
        string tmpPassword = username + rnd.Next(1000, 99999).ToString();
 
        string strSQL = "Update SingleSignOnUsers set password = @password where username = @username";
        SqlCommand cmd = new SqlCommand(strSQL, new SqlConnection(GetConnectionString()));
        cmd.CommandType = CommandType.Text;
 
        cmd.Parameters.Add(new SqlParameter("@password", tmpPassword));
        cmd.Parameters.Add(new SqlParameter("@username", username));
 
        cmd.Connection.Open();
        cmd.ExecuteNonQuery();
        cmd.Connection.Close();
    }
 
    private static string GetConnectionString()
    {
        return ConfigurationManager.ConnectionStrings["SingleSignOnDB"].ConnectionString;
    }

(For added security the page should be called using SSL (secure socket layer))

Create The DotNetNuke Application

In the DotNetNuke website, create a web reference to the web service created in the external application:

 

Next, create a custom module that calls the web service and creates the temporary password and a link to the external application, passing the username and temporary password as parameters:

        protected void lnkSingleSignOn_Click(object sender, EventArgs e)
        {
            Random rnd = new Random();
            string tmpPassword = txtUsername.Text + rnd.Next(1000, 99999).ToString();
 
            wsSingleSignOn.WebService wsSingleSignOn = new wsSingleSignOn.WebService();
            bool boolResponse = wsSingleSignOn.SetAuthendication(txtPassword.Text, txtUsername.Text, tmpPassword);
 
            Response.Redirect(String.Format("http://localhost/singleSignOn/SingleSignOn.aspx?username={0}&password={1}", txtUsername.Text, tmpPassword));
        }

In Conclusion

The solution described provides these benefits:

Complete source code

Due to the permissions issues in configuring the SQL Express database when it is moved from it's original location and that the DotNetNuke module code needs the web service link configured manually before it will compile, the download code is provided only as a reference.

DotNetNuke Module

External Application

Please note: It is impossible to assist all those who would have difficulty configuring this. Please us the forums for assistance.

The following companies have indicated that they have the ability to implement this solution:

http://dnnmasters.com

http://www.venexus.com

 

[Back to: The ADefWebserver DotNetNuke HELP WebSite]


DotNetNuke® is a registered trademark of DotNetNuke Corporation