BTI420 notes – Wed Mar 15

Some useful security-related topics today. And, graceful error-handling.

 

Test today

Test 8 is today, at the beginning of the timeslot, and will run approximately 18 minutes.

 

Code examples

Conditional Menus
Manage User Accounts
Personal Notes

 

Theme for this week

We will cover some useful security-related topics that will help you build better web apps.

We start with a general user interface topic – menu-building – and then move on to security topics.

Finally, we introduce a graceful way to handle runtime errors, without displaying scary information to browser users.

 

Special note about your work on Assignment 7

A few weeks ago, we wrote that you must NOT use the “virtual” keyword when defining navigation properties in your design model classes. This is a reminder.

 

Dropdown menu overview

We start with this topic, because we use it again soon, when we discuss security topics.

The Bootstrap framework enables you to predictably and easily create a dropdown menu. The technique is fully described in the Bootstrap documentation on “Dropdowns“.

Here’s a summary:

  • The menu choices in the dropdown are implemented as a nested unordered list
  • The top-level <li> uses a specific CSS class, and its content is an <a> that has specific attributes
  • The nested <ul> uses a specific CSS class
  • Its links can be generated by the ActionLink HTML Helper, or by normal <a> elements

Here’s the code for a typical implementation:

<div class="navbar-collapse collapse">
  <ul class="nav navbar-nav">
    <li>@Html.ActionLink("Home", "Index", "Home")</li>

    <li class="dropdown">
      <a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown for all users <b class="caret"></b></a>
      <ul class="dropdown-menu">
        <li><a href="#">Achieve world peace</a></li>
        <li><a href="#">Cure cancer</a></li>
        <li><a href="#">Solve the hunger problem</a></li>
      </ul>
    </li>

 

Here’s what it looks like as an image from the code editor. Click the image to open it full-size in a new tab/window.

menu-dropdown

 

Here’s how the menu is rendered, showing the new “Dropdown…” menu:

 

menu-conditional-closed

 

Here’s what it looks like when the “Dropdown…” menu item is clicked:

 

menu-conditional-open

 

Security topics that will get some love today

There’s a range of security topics that we’ll touch on today.

Some you can use immediately, including:

  • A way to easily expose information about the current authenticated user
  • Conditional menus
  • User account management

Some topics you can use soon, including:

  • Admin approval of a “register” request (the workflow)
  • Custom claim, and custom authorize attribute

And some advanced topics can be used in the near future, in another assignment, including:

  • Mixing user account concepts with real people (e.g. employees, customers)
  • Register new account works only for specific people
  • Restrict editing tasks to the owner of an object (in the data store)

 

Expose information about the current authenticated user –
RequestUser class, and usage in the Manager class and elsewhere

While studying this section, open the ConditionalMenus code example.

Open the Manager.cs source code file. Near the bottom, it has a class named RequestUser.

This class will make it far easier to expose often-used data in a user account. Sometimes you need the data to make a decision (e.g. does the user have the “Admin” role claim?), and sometimes you need the data for the user interface (e.g. the given name(s) and surname).

Again, this class just makes it easier to get to often-used data. It is a convenience class.

In a Manager property declaration, it creates one of these RequestUser objects the first time it’s accessed.

As the code comments state, you can use this property in the Manager class methods to control logic and flow, and to use its data/string content.

You can also use this property in a controller. For example:

var userName = m.User.Name;

 

You can also use this property in a view. For best results, near the top of the view (inside the typically existing @ { } code block), add this statement:

var userAccount = new <your-project-name>.Controllers.RequestUser
  (User as System.Security.Claims.ClaimsPrincipal);

 

Conditional menu items (and dropdowns)

As you know, the _Layout.cshtml asset is used to render the default layout for views in your app.

It includes a menu. The Bootstrap framework defines its appearance and behaviour.

We can add conditional menu choices to this menu. What condition? Anything you can imagine.

A popular condition is “security”. In other words, if a user is authenticated, or authenticated and has a specific role claim, you may want to show one or more menu items.

Above, you just learned (or were reminded) about the RequestUser object that you can configure in a view.

Its properties (and methods) can be used to make decisions about what to render, and its appearance.

For example, you can render a menu item if the request is authenticated. You can use Request.IsAuthenticated, or userAccount.IsAuthenticated. Either one is acceptable.

@if (Request.IsAuthenticated)
{
  <li>@Html.ActionLink("Account info", "Index", "Home")</li>
}

 

You can also  render a menu item (or a full dropdown menu) if the authenticated user has the “Admin” role claim.

@if (userAccount.IsAdmin)
{
  <li class="dropdown">
    <a href="#" class="dropdown-toggle" data-toggle="dropdown">Admin tasks <b class="caret"></b></a>
    <ul class="dropdown-menu">
      <li><a href="#">List of all users</a></li>
      <li><a href="#">Find user by name</a></li>
      <li><a href="#">Edit user info and claims</a></li>
    </ul>
  </li>
}

 

Finally, you can render a menu item based on any other logic or condition. You can even render strings from the userAccount object in the menu itself.

@if (userAccount.HasRoleClaim("Employee"))
{
  <li>@Html.ActionLink(userAccount.GivenName + " task", "Home", "Index")</li>
}

 

Here’s an image from the code editor that combines all these ideas. Click the image to open it full-size in a new tab/window.

menu-conditional

 

User account management

When your teacher team introduced the ASP.NET Identity system, we explained that it did not include a ready-to-use tool to, for example, manage user accounts.

Open the ManageAccounts code example, and study it as you read this section.

In the past, while you studied the Account and Manage controllers, you probably noticed the UserManager object. It is part of the in-memory security components, while your app is running.

Among other features, it enables:

  • a Users property, of all users
  • Find… methods, to locate a user by name or other search term
  • an AddClaim… method (which you have seen and used), to add a claim of any type
  • the ability to Delete a user

…and many other members to help you work with your app’s users.

The code example includes an AccountManager controller, and some views. (FYI – These may appear in a future version of the project template.) Run the app, create some users, and use the account management features. Study the code.

 

Restrict viewing and editing to the owner of an object

This is a common scenario, in all web apps (and web services): Restrict viewing and editing to the owner of an object.

Study the NotesApp code example while you read this section.

Almost all web apps enable users to work with public data, and data that is private to that user. This extends to any app that uses the web as a way to deliver data, for example, all the mobile apps that you use (Messages, Mail, Instagram, Facebook, etc.).

The methods in the Manager class are the key to implementing this behaviour.

They rely on entities that include user account identity/information in their schema. In the code example, there is a Note class, with an Owner property:

note-class

 

The value of the Owner property is set when the object is created.

Then, whenever we need to access the object, we must provide user account identity/information. For example, in the “get one” note method. Yes, look for the matching item by its identifier, but ALSO include the security check:

var o = ds.Notes.SingleOrDefault
  (n => n.Id == id && n.Owner == User.Name);

 

Controller code is unchanged from previous web apps. This new functionality is implemented in the Manager class only.

 

Handle request errors in an ASP.NET MVC web app

This section suggests an approach for gracefully handling request errors in an ASP.NET MVC web app. Inspiration for some of this was suggested by this StackOverflow answer.

 

What is the problem?

For new ASP.NET MVC programmers, two request errors are often seen:

  1. HTTP 404
  2. Server Error – An unhandled exception…

 

The first error – HTTP 404 – happens when a requested resource does not exist. Click the image to open it full-size in a new tab/window.

error-httpnotfound

 

The other happens when there’s a logic error in your code. For example, if you make a request that does not include a required argument (e.g. /products/details, without the /123 argument), you will see the following:

error-unhandled-exception

 

In both situations – and in any error situation – you must NOT show this error screen to users.

What should you do?

Add code to your project, so that a “not found” response looks similar to this:

error-http-404-formatted

 

And a ‘server error’ response looks similar to this, for browser users on the web:

error-unhandled-exception-formatted

 

For you – the programmer – a bit more information can be added, to help you locate the error:

error-unhandled-exception-formatted-localhost

 

 

Writing a suitable 404 page can be a serious yet amusing undertaking.

In a search engine, look for: 404 page custom or creative or best

Look at some of the results for inspiration.

Google has some suggestions on how to create a useful 404 page.

 

Also…

This suggested solution is not the last word on this topic.

It is enough for new ASP.NET MVC programmers, but it may not be enough for a production web app at scale.

There are third-party (via NuGet) error logging frameworks that can be added to a project, which offer more features and functionality.

 

Adding error-handling to a project

This solution is already in the “…V2” project template. Here’s how we did this:

We will add code to the project. We’ll add an ‘errors’ controller (and some views), and another (event handling) method in the MvcApplication class.

 

Add an “errors” controller

Add an errors controller; you can use the “empty” template.

Change its class declaration to include the “sealed” modifier:

public sealed class ErrorsController : Controller

 

Our solution will handle two types of errors:

  1. not found, and
  2. server error

 

Here’s some suggested code. We will use the ViewBag property to easily pass simple data to the view, and avoid the need to create view model classes.

 

 

Add views for “not found” and “server error”

Add views for the two methods. You can use the “empty” template.

Add your own content to make a useful page. You can implement the suggestions seen above.

 

Add methods to the MvcApplication class

We will write two methods in this class:

  1. an event-handler, for “end request”
  2. a private method, to initialize the errors controller, and call one of its methods

 

In an ASP.NET MVC 5 web app, the an instance of the MvcApplication class is created (by the ASP.NET runtime) when the first request is received. The app’s lifetime is twenty (20) minutes after receiving a request (and this timer is reset with each new request). At the end of the app’s lifetime, the ASP.NET runtime gracefully terminates the app.

The purpose of the MvcApplication class is to handle events that happen during the app’s lifetime. As a web app, all events are triggered during the handling of an HTTP request.

The Global.asax.cs source code file holds the definition of the MvcApplication class. It includes code for the Application_Start() method, which is called by the ASP.NET runtime to handle the Start event, and thereby begins the app’s lifetime.

We can write methods to handle other events. Which other events? A few are interesting now, and perhaps in the near future:

  • BeginRequest
  • EndRequest
  • Error
  • AuthenticateRequest
  • AuthorizeRequest

 

For this situation, we will write a method to handle the EndRequest event. How?

By convention, event-handling methods in the MvcApplication class return void, and have a composite name:

Application underscore event-name

Look at the Application_Start() method name as an example. To handle the EndRequest event, the declaration of its event-handling method will be:

protected void Application_EndRequest()

 

Here’s a sample implementation, which handles HTTP status codes 404 (not found) and anything above 500 (server error):

mvcapplication-end-request-method

 

To simplify the coding, and reduce code replication, the HandleError() method does most of the work:

mvcapplication-utility-method

 

Optional – resources, and more information

The following resources were used to inform and help assemble this document:

StackOverflow

MSDN – HttpApplication Class reference

MSDN – HttpApplication Events reference

MSDN – App Lifecycle Overview on IIS 5 and 6

MSDN – App Lifecycle Overview on IIS 7 (and 8)

K. Scott Allen – …the HttpApplication class

Andre Loker – HttpApplication instances

Sebastian Solnica – Global.asax in ASP.NET

 

More information about MvcApplication

An MvcApplication instance handles one request at a time.

The ASP.NET runtime will create additional instances of MvcApplication, to enable the app to handle multiple requests (in parallel) at the same time. How many? That number is set by default at the web server, and can be changed by an agreement between the app programmer(s) and the web site manager(s).

While there many be multiple instances of MvcApplication running, the Application_Start()method runs only once at the beginning of the app’s lifetime.

If you are using the MvcApplication class to initialize global (to the app) state (e.g. data, resources), be careful. Do the research. Make sure that you use the different kinds of app state storage appropriately. Recognize what kind of app state storage is global to the app (e.g.application state), and what kind of app state storage is local to a specific instance of an MvcApplication class (e.g. class-level properties and fields).

 

 

 

 

 

 

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Advertisements
%d bloggers like this: