Products

Solutions

Resources

Partners

Community

About

New Community Website

Ordinarily, you'd be at the right spot, but we've recently launched a brand new community website... For the community, by the community.

Yay... Take Me to the Community!

The Community Blog is a personal opinion of community members and by no means the official standpoint of DNN Corp or DNN Platform. This is a place to express personal thoughts about DNNPlatform, the community and its ecosystem. Do you have useful information that you would like to share with the DNN Community in a featured article or blog? If so, please contact .

The use of the Community Blog is covered by our Community Blog Guidelines - please read before commenting or posting.


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:

  • The solution provides single sign on for any domain configuration. and is able to cross any firewall.

  • The users real password is never transmitted over the network.

  • Once a temporary password has been used it is immediately changed. If a hacker attempts to guess temporary passwords, the password is changed each time so the hacker will be chasing a "moving target". 

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. Also, if you have any technical difficulties do not post to the blog please post to the forums.

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

http://dnnmasters.com
http://www.venexus.com

Comments

Comment Form

Only registered users may post comments.

NewsArchives


Aderson Oliveira (22)
Alec Whittington (11)
Alessandra Daniels (3)
Alex Shirley (10)
Andrew Hoefling (3)
Andrew Nurse (30)
Andy Tryba (1)
Anthony Glenwright (5)
Antonio Chagoury (28)
Ash Prasad (37)
Ben Schmidt (1)
Benjamin Hermann (25)
Benoit Sarton (9)
Beth Firebaugh (12)
Bill Walker (36)
Bob Kruger (5)
Bogdan Litescu (1)
Brian Dukes (2)
Brice Snow (1)
Bruce Chapman (20)
Bryan Andrews (1)
cathal connolly (55)
Charles Nurse (163)
Chris Hammond (213)
Chris Paterra (55)
Clint Patterson (108)
Cuong Dang (21)
Daniel Bartholomew (2)
Daniel Mettler (181)
Daniel Valadas (48)
Dave Buckner (2)
David Poindexter (12)
David Rodriguez (3)
Dennis Shiao (1)
Doug Howell (11)
Erik van Ballegoij (30)
Ernst Peter Tamminga (80)
Francisco Perez Andres (17)
Geoff Barlow (12)
George Alatrash (12)
Gifford Watkins (3)
Gilles Le Pigocher (3)
Ian Robinson (7)
Israel Martinez (17)
Jan Blomquist (2)
Jan Jonas (3)
Jaspreet Bhatia (1)
Jenni Merrifield (6)
Joe Brinkman (274)
John Mitchell (1)
Jon Henning (14)
Jonathan Sheely (4)
Jordan Coopersmith (1)
Joseph Craig (2)
Kan Ma (1)
Keivan Beigi (3)
Kelly Ford (4)
Ken Grierson (10)
Kevin Schreiner (6)
Leigh Pointer (31)
Lorraine Young (60)
Malik Khan (1)
Matt Rutledge (2)
Matthias Schlomann (16)
Mauricio Márquez (5)
Michael Doxsey (7)
Michael Tobisch (3)
Michael Washington (202)
Miguel Gatmaytan (3)
Mike Horton (19)
Mitchel Sellers (40)
Nathan Rover (3)
Navin V Nagiah (14)
Néstor Sánchez (31)
Nik Kalyani (14)
Oliver Hine (1)
Patricio F. Salinas (1)
Patrick Ryan (1)
Peter Donker (54)
Philip Beadle (135)
Philipp Becker (4)
Richard Dumas (22)
Robert J Collins (5)
Roger Selwyn (8)
Ruben Lopez (1)
Ryan Martinez (1)
Sacha Trauwaen (1)
Salar Golestanian (4)
Sanjay Mehrotra (9)
Scott McCulloch (1)
Scott Schlesier (11)
Scott Wilkinson (3)
Scott Willhite (97)
Sebastian Leupold (80)
Shaun Walker (237)
Shawn Mehaffie (17)
Stefan Cullmann (12)
Stefan Kamphuis (12)
Steve Fabian (31)
Steven Fisher (1)
Tony Henrich (3)
Torsten Weggen (3)
Tycho de Waard (4)
Vicenç Masanas (27)
Vincent Nguyen (3)
Vitaly Kozadayev (6)
Will Morgenweck (40)
Will Strohl (180)
William Severance (5)
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out