Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Real - World ASP .NET—Building a Content Management System - StephenR. G. Fraser

.pdf
Скачиваний:
68
Добавлен:
24.05.2014
Размер:
4.59 Mб
Скачать

{

foreach ( string role in roles)

{

if (role.Trim().Equals(dr["Role"].ToString().Trim()))

return true;

}

}

}

finally

{

m_Connection.Close();

}

m_ErrorMsg = "User not Authorized";

return false;

}

At this point, you have all the roles allowed to see the Web page and all the roles that the user performs. All it takes is a simple intersection of the two to find out whether authorization should be granted. The code does this by trying to find a strings match between the two lists. When the first equality happens, the method leaves with a true value.

The only thing that might catch a programmer's eye is that the return statement happens before the closing of the database connection. You might think that the close never occurs. This is not the case because it is within a try/finally exception clause that ensures that the statements within the finally clause are always completed (in this case, even without an exception occurring).

Update Setup3 for Authorization

Now that you have a roles database, you have to go back and revisit the setup procedure covered in Chapter 10. When you wrote this initially, you did not include the setting up of the role of administrator for the Administrator account.

The Codebehind for setup3 is nothing challenging, as you can see in Listings 12-11 and 12-12.

Listing 12-11: The Setup3 Codebehind Page_Load Method Authorization Changes

private void Page_Load(object sender, System.EventArgs e)

{

if (IsPostBack)

{

Page.Validate();

if (Page.IsValid)

{

try

{

...

ProcessAdministratorName();

ProcessAccountRoles();

Response.Redirect("setup4.aspx");

}

}

}

}

Listing 12-12: The New Setup3 Codebehind ProcessAccountRoles Method

private void ProcessAccountRoles()

{

try

{

role.Insert(1, "Administrator");

}

catch (SqlException)

{

// Duplicate key means jobs done already ... move on.

}

}

As you can see in Listing 12-13, the AccountRoles database help Insert() method is not much different from any of the others you have previously seen.

Listing 12-13: The AccountRoles Database Helper Insert Method

public void Insert(int AccountID, string Role)

{

// INSERT

// INTO AccountRoles ( AccountID, Role, ModifiedDate, CreationDate)

// VALUES (@AccountID, @Role, @ModifiedDate, @CreationDate)

SqlCommand Command = new SqlCommand("AccountRoles_Insert", m_Connection); Command.CommandType = CommandType.StoredProcedure;

Command.Parameters.Add(new SqlParameter("@AccountID", SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@Role", SqlDbType.Char, 32));

Command.Parameters.Add(new SqlParameter("@CreationDate",

SqlDbType.DateTime));

Command.Parameters["@AccountID"].Value = AccountID;

Command.Parameters["@Role"].Value = Role;

Command.Parameters["@CreationDate"].Value = DateTime.Now;

try

{

m_Connection.Open();

Command.ExecuteNonQuery();

}

finally

{

m_Connection.Close();

}

}

Encryption

Passwords are usually stored encrypted. .NET provides two different encryption algorithms to encrypt passwords:

§MD5: Generates Message Digest 5 hash code. This algorithm is the faster of the two provided by .NET.

§SHA1: Generates a Secure Hash Algorithm 1 hash code. This algorithm is the more secure of the two.

To encrypt a password, you use a method with the overly lengthy name of

HashPasswordForStoringInConfigFile(). Encryption is a one-way street for these two algorithms. There is no decrypting method.

web.config Credentials Element

For people who decide to use ASP.NET's method of authorization instead of the one used by CMS.NET, it is possible to store the credentials of a user using an encrypted password. Listing 12-14 shows credentials using a SHA1 encryption on the passwords. It is also possible to use MD5 encryption instead.

Listing 12-14: SHA1 Password-Encrypted Credentials

<credentials passwordFormat="SHA1" >

<user name="Admin"

password="B34272C363EADA35031C69B6825C1CCF16154D67" />

<user name="sfraser" password="5D1FF37BC03988F4A679117E75FD035759B2CBA6"

/>

</credentials>

As of this book's printing, there still is no method provided by ASP.NET (other than standard XML) to add credentials to web.config. You currently have two options: write the XML to update web.config or generate a script that dumps out the encrypted version of a password to screen or file so that you can paste it manually into the web.config file.

Updating Account Database Helper Methods for Encryption

All encryption code for CMS.NET is located in the Account helper class, so let's visit it one more time.

As you can see in Listings 12-15 and 12-16, the code updated in the Insert() and Update() methods is exactly the same. The code uses a little cheat. All SHA1 encryptions generate a hash code of exactly 40 characters. Thus, it is possible to see if the value passed into the methods contains an already-encrypted password or an unencrypted version by checking its length. Unencrypted passwords have a maximum length of 16 characters, which is enforced by the MaxLength property of the password

entry fields. Therefore, whenever the password is not equal to 40, it gets encrypted before it is placed in the database.

Listing 12-15: Account Database Helper Insert Method with Encryption

public void Insert(string UserName, string Password, string Email)

{

// INSERT INTO Account (UserName, Password, Email, // ModifiedDate, CreationDate)

// VALUES (@UserName, @Password, @Email, @ModifiedDate, @CreationDate)

SqlCommand Command = new SqlCommand("Account_Insert", m_Connection); Command.CommandType = CommandType.StoredProcedure;

Command.Parameters.Add(new SqlParameter("@UserName", SqlDbType.Char, 32));

Command.Parameters.Add(new SqlParameter("@Password", SqlDbType.Char, 40));

Command.Parameters.Add(new SqlParameter("@Email", SqlDbType.Char, 64));

Command.Parameters.Add(new SqlParameter("@ModifiedDate",

SqlDbType.DateTime));

Command.Parameters.Add(new SqlParameter("@CreationDate",

SqlDbType.DateTime));

Command.Parameters["@UserName"].Value = UserName;

if (Password.Length == 40)

{

Command.Parameters["@Password"].Value = Password;

}

else

{

Command.Parameters["@Password"].Value =

FormsAuthentication.HashPasswordForStoringInConfigFile

(Password, "SHA1");

}

Command.Parameters["@Email"].Value = Email;

Command.Parameters["@ModifiedDate"].Value = DateTime.Now;

Command.Parameters["@CreationDate"].Value = DateTime.Now;

try

{

m_Connection.Open();

Command.ExecuteNonQuery();

}

finally

{

m_Connection.Close();

}

}

Listing 12-16: Account Database Helper Update Method with Encryption

public void Update(int AccountID, string UserName, string Password, string Email)

{

//UPDATE Account

//

SET UserName

= @UserName,

//

Password

 

= @Password,

//

Email

= @Email,

//ModifiedDate = @ModifiedDate

//WHERE AccountID = @AccountID

SqlCommand Command = new SqlCommand("Account_Update", m_Connection); Command.CommandType = CommandType.StoredProcedure;

Command.Parameters.Add(new SqlParameter("@AccountID", SqlDbType.Int));

Command.Parameters.Add(new SqlParameter("@UserName", SqlDbType. Char, 32));

Command.Parameters.Add(new SqlParameter("@Password", SqlDbType.Char, 40));

Command.Parameters.Add(new SqlParameter("@Email", SqlDbType.Char, 64));

Command.Parameters.Add(new SqlParameter("@ModifiedDate",

SqlDbType.DateTime));

Command.Parameters["@AccountID"].Value = AccountID;

Command.Parameters["@UserName"].Value = UserName;

if (Password.Length == 40)

{

Command.Parameters["@Password"].Value = Password;

}

else

{

Command.Parameters["@Password"].Value = FormsAuthentication.HashPasswordForStoringInConfigFile (Password, "SHA1");

}

Command.Parameters["@Email"].Value = Email;

Command.Parameters["@ModifiedDate"].Value = DateTime.Now;

try

{

m_Connection.Open();

Command.ExecuteNonQuery();

}

finally

{

m_Connection.Close();

}

}

The last place that encryption is used is in the Authenticated() method (see Listing 12-17). Whenever you receive a password in the authentication form, it comes unencrypted. Therefore, to verify that the password matches the value in the database, it needs to be encrypted.

Listing 12-17: Account Database Helper Authenticated Method with Encryption

public bool Authenticated(string username, string password)

{

//SELECT Password

//FROM Account

//WHERE UserName=@username

bool ret = false;

SqlCommand Command = new SqlCommand("Account_Authenticated", m_Connection); Command.CommandType = CommandType.StoredProcedure;

Command.Parameters.Add(new SqlParameter("@username", SqlDbType.Char, 32)); Command.Parameters["@username"].Value = username;

try

{

m_Connection.Open();

SqlDataReader dr = Command.ExecuteReader();

if (dr.Read())

{

if(dr["Password"].ToString().Equals( FormsAuthentication.HashPasswordForStoringInConfigFile (password, "SHA1")))

{

ret = true;

}

else

{

m_ErrorMsg = "Invalid password";

}

}

else

{

m_ErrorMsg = "User Name not found."; ret = false;

}

}

finally

{

m_Connection.Close();

}

return ret;

}

If you have already run the setup routine for CMS.NET, you will have to rerun it now so that your admin account will be able to log back in. The reason is that the authentication routine has been changed to look for an encrypted password but the admin password, in the databases, is readable text. Simply setting the value of the setup key to false in your root copy of web.config and then setting up CMS.NET again by executing the Web page will fix this problem.

Remember, SHA1 is a one-way encryption. Therefore, the only way to see if both passwords match is to encrypt both the database password and the authentication check password.

Warning

Restricting the CMA

Okay, you have all the code needed to support different users and roles. Let's put it into practice by restricting the CMA directory to be available only to administrators and authors. The first step is to add a web.config file that authorizes only the roles of administrator and author to the CMA directory developed in Chapter 11.

Next, change all the Aut Web page Codebehind to inherit AuthorizedPage.

Not much of a challenge, I would say.

NavBar Update for Handling Roles

When you create a NavBar, it doesn't make sense to allow navigation to areas of the Web site for which the user does not have authorization. This will only confuse and frustrate the user. So let's give NavBar.aspx a minor facelift so that it only displays menus the user can access.

First, you need to make a small change to CMAMenu.xml (see Listing 12-18). You need to add an optional element of <authorization> directly after the <Menu> element. If this element is present, the NavBar will only present the menu if the user has authorization. To keep compatibility with the previous version, all users can see a menu

if no <authorization> element is present.

Listing 12-18: Updated CMAMenu.xml with Authorization

<?xml version="1.0" encoding="utf-8" ?> <MainMenu>

<Menu>

<authorization>Administrator</authorization> <MenuName>Account Admin</MenuName> <MenuItem>

<Name>List Accounts</Name>

<Link>AdmAcnt/AdmAcntList.aspx</Link>

</MenuItem> <MenuItem>

<Name>Create Account </Name>

<Link>AdmAcnt/AdmAcntCreate.aspx</Link>

</MenuItem>

</Menu>

<Menu>

<authorization>Administrator,Author</authorization>

Соседние файлы в предмете Программирование