Wednesday, November 24, 2021

mvc security

 In this chapter, we will discuss how to implement security features in the application. We will also look at the new membership features included with ASP.NET and available for use from ASP.NET MVC. In the latest release of ASP.NET, we can manage user identities with the following −

  • Cloud
  • SQL database
  • Local Windows active directory

In this chapter, we will also take a look at the new identity components that is a part of ASP.NET and see how to customize membership for our users and roles.

Authentication

Authentication of user means verifying the identity of the user. This is really important. You might need to present your application only to the authenticated users for obvious reasons.

Let’s create a new ASP.Net MVC application.

New MVC Application

Click OK to continue.

When you start a new ASP.NET application, one of the steps in the process is configuring the authentication services for application needs.

Select MVC template and you will see that the Change Authentication button is now enabled.

Authentication Button Enabled

This is done with the Change Authentication button that appears in the New Project dialog. The default authentication is, Individual User Accounts.

Authentication Options

When you click the Change button, you will see a dialog with four options, which are as follows.

No Authentication

The first option is No Authentication and this option is used when you want to build a website that doesn't care who the visitors are.

No Authentication

It is open to anyone and every person connects as every single page. You can always change that later, but the No Authentication option means there will not be any features to identify users coming to the website.

Individual User Accounts

The second option is Individual User Accounts and this is the traditional forms-based authentication where users can visit a website. They can register, create a login, and by default their username is stored in a SQL Server database using some new ASP.NET identity features, which we'll look at.

Individual User Accounts

The password is also stored in the database, but it is hashed first. Since the password is hashed, you don't have to worry about plain-text passwords sitting in a database.

This option is typically used for internet sites where you want to establish the identity of a user. In addition to letting a user create a local login with a password for your site, you can also enable logins from third parties like Microsoft, Google, Facebook, and Twitter.

This allows a user to log into your site using their Live account or their Twitter account and they can select a local username, but you don't need to store any passwords.

This is the option that we'll spend some time with in this module; the individual user accounts option.

Work and School Accounts

The third option is to use organizational accounts and this is typically used for business applications where you will be using active directory federation services.

Work School Accounts

You will either set up Office 365 or use Azure Active Directory Services, and you have a single sign-on for internal apps and Cloud apps.

You will also need to provide an app ID so your app will need to be registered with the Windows Azure management portal if this is Azure based, and the app ID will uniquely identify this application amongst all the applications that might be registered.

Windows Authentication

The fourth option is Windows authentication, which works well for intranet applications.

Windows Authentication

A user logs into Windows desktop and can launch a browser to the application that sits inside the same firewall. ASP.NET can automatically pick up the user's identity, the one that was established by active directory. This option does not allow any anonymous access to the site, but again that is a configuration setting that can be changed.

Let's take a look into the forms-based authentication, the one that goes by the name, Individual User Accounts. This application will store usernames and passwords, old passwords in a local SQL Server database, and when this project is created, Visual Studio will also add NuGet packages.

Forms-based Authentication

Now run this application and when you first come to this application you will be an anonymous user.

Anonymous User

You won't have an account that you can log into yet so you will need to register on this site.

Click on the Register link and you will see the following view.

Click Register Link

Enter your email id and password.

Enter EmailId Password

Click Register. Now, the application will recognize you.

Click Register

It will be able to display your name. In the following screenshot, you can see Hello, muhammad.waqas@outlook.com! is displayed. You can click on that and it's a link to a page where you can change the password.

Display Your Name

You can also log off, shut down, reboot, come back a week later, and you should be able to log in with the credentials that you used earlier. Now click on the log off button and it will display the following page.

Click Logoff Button

Click again on the Log in link and you will go to the following page.

Click Login Link

You can login again with the same credentials.

A lot of work goes on behind the scene to get to this point. However, what we want to do is examine each of the features and see how this UI is built. What is managing the logoff and the login process? Where is this information sorted in the database?

Let's just start with a couple of simple basics. First we will see how is this username displayed. Open the _Layout.cshtml from the View/Shared folder in the Solution explorer.

<!DOCTYPE html>
<html>
   <head>
      <meta charset = "utf-8" />
      <meta name = "viewport" content = "width = device-width, initial-scale = 1.0">
      <title>@ViewBag.Title - My ASP.NET Application</title>
      @Styles.Render("~/Content/css")
      @Scripts.Render("~/bundles/modernizr")
   </head>
	
   <body>
      <div class = "navbar navbar-inverse navbar-fixed-top">
         <div class = "container">
			
            <div class = "navbar-header">
               <button type = "button" class = "navbar-toggle" datatoggle = "collapse"
                  data-target = ".navbar-collapse">
                     <span class = "icon-bar"></span>
                     <span class = "icon-bar"></span>
                     <span class = "icon-bar"></span>
               </button>
					
               @Html.ActionLink("Application name", "Index", "Home", new
               { area = "" }, new { @class = "navbar-brand" })
            </div>
				
            <div class = "navbar-collapse collapse">
               <ul class = "nav navbar-nav">
                  <li>@Html.ActionLink("Home", "Index", "Home")</li>
                  <li>@Html.ActionLink("About", "About", "Home")</li>
                  <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
               </ul>
					
               @Html.Partial("_LoginPartial")
            </div>
				
         </div>
			
      </div>
      <div class = "container body-content">
         @RenderBody()
         <hr />
         <footer>
            <p>© @DateTime.Now.Year - My ASP.NET Application</p>
         </footer>
      </div>
		
      @Scripts.Render("~/bundles/jquery")
      @Scripts.Render("~/bundles/bootstrap")
      @RenderSection("scripts", required: false)
		
   </body>
</html>

There is a common navigation bar, the application name, the menu, and there is a partial view that's being rendered called _loginpartial. That's actually the view that displays the username or the register and login name. So _loginpartial.cshtml is also in the shared folder.

@using Microsoft.AspNet.Identity
@if (Request.IsAuthenticated) {
   using (Html.BeginForm("LogOff", "Account", FormMethod.Post,
      new { id = "logoutForm", @class = "navbar-right" })){
         @Html.AntiForgeryToken()
         <ul class = "nav navbar-nav navbar-right">
            <li>
               @Html.ActionLink("Hello " + User.Identity.GetUserName() + "!",
               "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
            </li>
				
            <li>
               <a href = "javascript:document.getElementById('logoutForm').submit()">Logoff</a>
            </li>
				
         </ul>
      }
}else{
   <ul class = "nav navbar-nav navbar-right">
      <li>@Html.ActionLink("Register", "Register", "Account", routeValues:
         null, htmlAttributes: new { id = "registerLink" })</li>
			
      <li>@Html.ActionLink("Log in", "Login", "Account", routeValues: null,
         htmlAttributes: new { id = "loginLink" })</li>
   </ul>
}

As you can see above, there are if/else statements. If we do not know who the user is, because the request is not authenticated, this view will display register and login links. The user can click on the link to log in or register. All this is done by the account controller.

For now, we want to see how to get the username, and that's inside Request.IsAuthenticated. You can see a call to User.Identity.GetUserName. That will retrieve the username, which in this case is ‘muhammad.waqas@outlook.com’

Authorization

Let's suppose that we have some sort of information which we want to protect from unauthenticated users. So let’s create a new controller to display that information, but only when a user is logged in.

Right-click on the controller folder and select Add → Controller.

User Logged in

Select an MVC 5 controller - Empty controller and click ‘Add’.

Enter the name SecretController and click ‘Add’ button.

SecretController

It will have two actions inside as shown in the following code.

using System.Web.Mvc;

namespace MVCSecurityDemo.Controllers{
   public class SecretController : Controller{
      // GET: Secret
      public ContentResult Secret(){
         return Content("Secret informations here");
      }
		
      public ContentResult PublicInfo(){
         return Content("Public informations here");
      }
   }
}

When you run this application, you can access this information without any authentication as shown in the following screenshot.

Secret Information Here

So only authenticated users should be able to get to Secret action method and the PublicInfo can be used by anyone without any authentication.

To protect this particular action and keep unauthenticated users from arriving here, you can use the Authorize attribute. The Authorize attribute without any other parameters will make sure that the identity of the user is known and they're not an anonymous user.

// GET: Secret
[Authorize]
public ContentResult Secret(){
   return Content("Secret informations here");
}

Now run this application again and specify the same URL http://localhost:54232/Secret/Secret. The MVC application will detect that you do not have access to that particular area of the application and it will redirect you automatically to the login page, where it will give you a chance to log in and try to get back to that area of the application where you were denied.

Redirect Automatically Login Page

You can see that it is specified in the return URL, which essentially tells this page that if the user logs in successfully, redirect them back to /secret/secret.

Enter your credentials and click ‘Log in’ button. You will see that it goes directly to that page.

Secret Information Here

If you come back to the home page and log off, you cannot get to the secret page. You will be asked again to log in, but if go to /Secret/PublicInfo, you can see that page, even when you are not authenticated.

Public Information Here

So, when you don't want to be placing authorization on every action when you're inside a controller where pretty much everything requires authorization. In that case you can always apply this filter to the controller itself and now every action inside of this controller will require the user to be authenticated.

using System.Web.Mvc;

namespace MVCSecurityDemo.Controllers{
   [Authorize]
   public class SecretController : Controller{
      // GET: Secret
      public ContentResult Secret(){
         return Content("Secret informations here");
      }
		
      public ContentResult PublicInfo(){
         return Content("Public informations here");
      }
   }
}

But if you really want any action to be open, you can come override this authorization rule with another attribute, which is, AllowAnonymous.

using System.Web.Mvc;

namespace MVCSecurityDemo.Controllers{
   [Authorize]
   public class SecretController : Controller{
      // GET: Secret
      public ContentResult Secret(){
         return Content("Secret informations here");
      }
		
      [AllowAnonymous]
      public ContentResult PublicInfo(){
         return Content("Public informations here");
      }
   }
}

Run this application and you can access the /Secret/PublicInfo with logging in but other action will require authentication.

Public Information Here

It will allow anonymous users into this one action only.

With the Authorize attribute, you can also specify some parameters, like allow some specific users into this action.

using System.Web.Mvc;

namespace MVCSecurityDemo.Controllers{
   [Authorize(Users = "ali.khan@outlook.com")]
   public class SecretController : Controller{
      // GET: Secret
      public ContentResult Secret(){
         return Content("Secret informations here");
      }
		
      [AllowAnonymous]
      public ContentResult PublicInfo(){
         return Content("Public informations here");
      }
   }
}

When you run this application and go to /secret/secret, it will ask you to log in because it is not the proper user for this controller.

Go to Secret

MVC RAZOR

 In this chapter, we will look at the Razor view engine in ASP.NET MVC applications and some of the reasons why Razor exists. Razor is a markup syntax that lets you embed server-based code into web pages using C# and VB.Net. It is not a programming language. It is a server side markup language.

Razor has no ties to ASP.NET MVC because Razor is a general-purpose templating engine. You can use it anywhere to generate output like HTML. It's just that ASP.NET MVC has implemented a view engine that allows us to use Razor inside of an MVC application to produce HTML.

View Engine

You will have a template file that's a mix of some literal text and some blocks of code. You combine that template with some data or a specific model where the template specifies where the data is supposed to appear, and then you execute the template to generate your output.

Razor Vs ASPX

  • Razor is very similar to how ASPX files work. ASPX files are templates, which contain literal text and some C# code that specifies where your data should appear. We execute those to generate the HTML for our application.

  • ASPX files have a dependency on the ASP.NET runtime to be available to parse and execute those ASPX files. Razor has no such dependencies.

  • Unlike ASPX files, Razor has some different design goals.

Goals

Microsoft wanted Razor to be easy to use and easy to learn, and work inside of tools like Visual Studio so that IntelliSense is available, the debugger is available, but they wanted Razor to have no ties to a specific technology, like ASP.NET or ASP.NET MVC.

If you're familiar with the life cycle of an ASPX file, then you're probably aware that there's a dependency on the ASP.NET runtime to be available to parse and execute those ASPX files. Microsoft wanted Razor to be smart, to make a developer's job easier.

Let’s take a look at a sample code from an ASPX file, which contains some literal text. This is our HTML markup. It also contains little bits of C# code.

<% foreach (var item in Model) { %>
   <tr>
      <td>
         <%: Html.ActionLink("Edit", "Edit", new { id = item.ID })%> |
         <%: Html.ActionLink("Details", "Details", new { id = item.ID }) %>|
         <%: Html.ActionLink("Delete", "Delete", new { id = item.ID })%>
      </td>
		
      <td>
         <%: item.Name %>
      </td>
		
      <td>
         <%: String.Format("{0,g}", item.JoiningDate) %>
      </td>
		
   </tr>
<%}%>

But these Web forms were basically repurposed by Microsoft to work with the earlier releases of MVC, meaning ASPX files were never a perfect match for MVC.

The syntax is a bit clunky when you need to transition from C# code back to HTML and from HTML code back into C# code. You are also prompted by IntelliSense to do things that just don't make sense in an MVC project, like add directives for output caching and user controls into an ASPX view.

Now look at this code which produces the same output, the difference being it is using the Razor syntax.

@foreach (var item in Model) {
   <tr>
      <td>
         @Html.ActionLink("Edit", "Edit", new { id = item.ID }) |
         @Html.ActionLink("Details", "Details", new { id = item.ID }) |
         @Html.ActionLink("Delete", "Delete", new { id = item.ID })
      </td>
		
      <td>
         @item.Name
      </td>
		
      <td>
         @String.Format("{0,g}", item.JoiningDate)
      </td>
   </tr>
}

With Razor syntax you can begin a bit of C# code by using the ‘@’ sign and the Razor parse will automatically switch into parsing this statement, this foreach statement, as a bit of C# code.

But when we're finished with the foreach statement and we have our opening curly brace, we can transition from C# code into HTML without putting an explicit token in there, like the percent in the angle bracket signs.

The Razor parser is smart enough to switch between C# code and HTML and again, from HTML back into C# code when we need to place our closing curly brace here. If you compare these two blocks of code, I think you'll agree that the Razor version is easier to read and easier to write.

Creating a View Using Razor

Let's create a new ASP.Net MVC project.

Razor MVC Project

Enter the name of project in the name field and click Ok.

project_name

To keep things simple, select the Empty option and check the MVC checkbox in the ‘Add folders and core references for’ section and click Ok. It will create a basic MVC project with minimal predefined content.

Once the project is created by Visual Studio, you will see a number of files and folders displayed in the Solution Explorer window. As we have created ASP.Net MVC project from an empty project template, so at the moment the application does not contain anything to run. Since we start with an empty application and don't even have a single controller, let’s add a HomeController.

To add a controller right-click on the controller folder in the solution explorer and select Add → Controller. It will display the Add Scaffold dialog.

Razor Controller Folder

Select the MVC 5 Controller – Empty option and click Add button and then the Add Controller dialog will appear.

HomeController

Set the name to HomeController and click ‘Add’ button. You will see a new C# file ‘HomeController.cs’ in the Controllers folder, which is open for editing in Visual Studio as well.

Editing in Visual Studio

Right-click on the Index action and select Add View…

Index Action Add View

Select Empty from the Template dropdown and click Add button. Visual Studio will create an Index.cshtml file inside the View/Home folder.

Create Index.cshtml

Notice that Razor view has a cshtml extension. If you're building your MVC application using Visual Basic it will be a VBHTML extension. At the top of this file is a code block that is explicitly setting this Layout property to null.

When you run this application you will see the blank webpage because we have created a View from an Empty template.

Blank Webpage

Let's add some C# code to make things more interesting. To write some C# code inside a Razor view, the first thing we will do is type the ‘@’ symbol that tells the parser that it is going to be doing something in code.

Let's create a FOR loop specify ‘@i’ inside the curly braces, which is essentially telling Razor to put the value of i.

@{
   Layout = null;
} 

<!DOCTYPE html>
<html>
   <head>
      <meta name = "viewport" content = "width = device-width" />
      <title>Index</title>
   </head>
	
   <body>
      <div>
         @for (int index = 0; index < 12; index++){
            <div>@index </div>
         }
      </div>
   </body>
	
</html>

Run this application and you will see the following output.

Razor Output

MVC VALIDATION

 Validation is an important aspect in ASP.NET MVC applications. It is used to check whether the user input is valid. ASP.NET MVC provides a set of validation that is easy-to-use and at the same time, it is also a powerful way to check for errors and, if necessary, display messages to the user.

DRY

DRY stands for Don't Repeat Yourself and is one of the core design principles of ASP.NET MVC. From the development point of view, it is encouraged to specify functionality or behavior only at one place and then it is used in the entire application from that one place.

This reduces the amount of code you need to write and makes the code you do write less error prone and easier to maintain.

Adding Validation to Model

Let’s take a look at a simple example of validation in our project from the last chapter. In this example, we will add data annotations to our model class, which provides some builtin set of validation attributes that can be applied to any model class or property directly in your application, such as Required, StringLength, RegularExpression, and Range validation attributes.

It also contains formatting attributes like DataType that help with formatting and don't provide any validation. The validation attributes specify behavior that you want to enforce on the model properties they are applied to.

The Required and MinimumLength attributes indicates that a property must have a value; but nothing prevents a user from entering white space to satisfy this validation. The RegularExpression attribute is used to limit what characters can be input.

Let’s update Employee class by adding different annotation attributes as shown in the following code.

using System;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;

namespace MVCSimpleApp.Models {
   public class Employee{
      public int ID { get; set; }
      [StringLength(60, MinimumLength = 3)]
		
      public string Name { get; set; }
      [Display(Name = "Joining Date")]
      [DataType(DataType.Date)]
      [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}",
		
      ApplyFormatInEditMode = true)]
      public DateTime JoiningDate { get; set; }
      [Range(22, 60)]
      public int Age { get; set; }
   }
}

Now we also need to set limits to the database. However, the database in SQL Server Object Explorer shows the name property is set to NVARCHAR (MAX) as seen in the following screenshot.

NVARCHAR (MAX)

To set this limitation on the database, we will use migrations to update the schema.

Open the Package Manager Console window from Tools → NuGet Package Manager → Package Manager Console.

Package Manager Console

Enter the following commands one by one in the Package Manager Console window.

Enable-Migrations
add-migration DataAnnotations
update-database

Following is the log after executing these commands in Package Manager Console window.

Package Manager Console Window

Visual Studio will also open the class which is derived from the DbMIgration class in which you can see the code that updates the schema constraints in Up method.

namespace MVCSimpleApp.Migrations {
   using System;
   using System.Data.Entity.Migrations;
	
   public partial class DataAnnotations : DbMigration{
      public override void Up(){
         AlterColumn("dbo.Employees", "Name", c => c.String(maxLength: 60));
      }
		
      public override void Down(){
         AlterColumn("dbo.Employees", "Name", c => c.String());
      }
   }
}

The Name field has a maximum length of 60, which is the new length limits in the database as shown in the following snapshot.

New Length Limits

Run this application and go to Create view by specifying the following URL http://localhost:63004/Employees/Create

Localhost Employees Create

Let’s enter some invalid data in these fields and click Create Button as shown in the following screenshot.

Enter Invalid Data

You will see that jQuery client side validation detects the error, and it also displays an error message.

GRIDVIEW ON ROW DATA BOUND EVENT

 Database Create  Student : roll , name , city , cost  Fix 6 Value  in Database Record  ====================================================...