Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Secure Your ASP.NET Application With Authorization From Okta

DZone's Guide to

Secure Your ASP.NET Application With Authorization From Okta

Secure authentication is only half of the battle. In this post, you’ll learn how to implement authorization in your ASP.NET Core MVC app simply.

· Security Zone ·
Free Resource

Discover how to provide active runtime protection for your web applications from known and unknown vulnerabilities including Remote Code Execution Attacks.

Let's be honest. Secure authentication is only half of the battle. Authorization is just as important to secure identity management but is often forgotten. In reality, almost every app needs more than just “is this user signed in?” Most times, you need to not know who the user is, AND what access they are supposed to have. In this tutorial, you’ll learn how to implement authorization in your ASP.NET Core MVC app simply, with Okta.

In the Okta world, users are separated into Groups. By default, however, ASP.NET only has handling for the Authorizeattribute to handle authorization using Roles. There are a couple of ways you could go about handling authorization using the Groups that come from Okta:

  • You can write your own custom AuthorizeAttribute and have it look at groups instead of roles.
  • You can map the Groups to Roles claims and let the regular ASP.NET AuthorizeAttribute handle authorization.

This second approach is far easier to implement, so that’s the approach this article will take.

Start by cloning the application from GitHub. This is the base application with authentication covered in my previous post. You’ll add authorization to this application.

Let ASP.NET Know Where Your Roles Are

In the startup.cs file, where the OpenIdConfigurationOptions are set, one of the items being set is the TokenValidationParameters. In the new TokenValidationParameters, add a property called RoleClaimTypewith a value of ClaimTypes.Role. This is an enumeration in the System.Security.Claims namespace that holds the URL that describes the “role” claim type. Ultimately, your TokenValidationParameters property should look like this.

TokenValidationParameters = new TokenValidationParameters
{
  ValidateIssuer = true,
  RoleClaimType = ClaimTypes.Role
}

Add a Claims Transformer

The Claims Transformer is a way to manipulate the ClaimsPrincipal, which is the main user in your ASP.NET application, once the user is authenticated.

Add a folder inside the Domain folder called Authorization. Then add a class called GroupsToRolesTransformer. The contents of the transformer should be:

using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Okta.Sdk;
using Okta.Sdk.Configuration;

namespace AspnetOkta.Domain.Authorization
{
  public class GroupsToRolesTransformer : IClaimsTransformer
  {
    private OktaClient client;

    public GroupsToRolesTransformer()
    {
        client = new OktaClient(new OktaClientConfiguration{
            OrgUrl = "https://{Your Okta Org Url}",
            Token = "JiBBerJabbER"
        });
    }

    public async Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context)
    {
      var idClaim = context.Principal.FindFirst(x=>x.Type == ClaimTypes.NameIdentifier);
      if(idClaim != null)
      {
          var user = await client.Users.GetUserAsync(idClaim.Value);
          if(user != null){
            var groups = user.Groups.ToEnumerable();
            foreach (var group in groups)
            {
                ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim(ClaimTypes.Role, group.Profile.Name));
            }
          }
      }
      return context.Principal;
    }
  }
}

As you can see here, in the constructor, you are creating an OktaClient object to be stored in a class-level variable called client. You’ll need your OrgUrl from Okta (probably something like dev-1234.oktapreview.com) and an API token which you can get from the Okta Developer Dashboard under API > Tokens.

API Token Page

Be aware that you only get to see the API token when you create it, so make sure you save it somewhere so you can reference it later.

Once you’ve created a transformer, it will implement the IClaimsTransformer interface. There is only one method you’ll need to worry about, and that’s the TransformAsync method. It takes a ClaimsTransformationContext and returns a Task with a ClaimsPrincipal in it.

Note that if you use the key shortcuts to get Visual Studio (or Visual Studio Code) to implement the interface for you, it will not add the public or async keywords to the signature. You’ll have to add them manually.

In this method, you’ll get the currently authenticated user’s NameIdentifier property. This is the ID you’ll use to get the Okta user so that you can get their groups. Just a quick null check for the idClaim variable and then go and get the Groups from the user object. From there, simply loop through the Groups and add a Claim using the ClaimTypes.Roleenumeration and using the group.Profile.Name for the value of the claim.

Return the context.Principal no matter what. If you didn’t find the user’s identifier, or get a user back from the GetUserAsynccall, at least the application will still get the ClaimsPrincipal back into the flow of the application.

Tell the Application to Use Your Transformer

The only thing left is to configure your application to use the new transformer in your middleware pipeline.

Right below the OIDC setup in the Configure method of your startup.cs file, add the following code:

app.UseClaimsTransformation(new ClaimsTransformationOptions{
  Transformer = new GroupsToRolesTransformer()
});

This tells the application that you want to transform the claims and which claims transformer you want to use.

Prove That it Works

You’ll need to set up two users in two different groups in your Okta Developer Dashboard. Call one group “Admin” and the other “Enthusiast.”

Add Groups Page

Make sure the groups are assigned to your application:

Assing Groups To Application

Then create some routes in the UserController decorated with the AuthorizeAttribute.

  [Authorize(Roles = "Admin")]
  public IActionResult AdminOnly()
  {
    return View();
  }

  [Authorize(Roles = "Enthusiast")]
  public IActionResult EnthusiastOnly()
  {
    return View();
  }

Then create matching views for those routes.

AdminOnly.cshtml

<h1>Admin Dashboard</h1>

EnthusiastOnly.cshtml

<h1>Enthusiast Dashboard</h1>

Now you should be able to run your application, log in as a user in the “Admin” group, and go to the http://localhost:5000/User/AdminOnly route successfully. The EnthusiastOnly route should return an unauthorized error.

Log back out and log in as a member of the “Enthusiast” group and go to the http://localhost:5000/User/EnthusiastOnly URL, and you should be able to get to it.

Congratulations! You just added authorization to you .NET application! Not only can users get into your application, but you can make sure they have access to the data and functionality they need!

Learn More

You can learn more about the .NET Claims Transformer in the Microsoft Docs and the broader spectrum of security in .NET here.

And don’t forget, Okta can help you make user management simple! Sign up for a free forever developer account! As always, if you have questions about anything here, feel free to reach out on Twitter.

User Authorization in ASP.NET Core with Okta was originally published on the Okta developer blog on October 4, 2017.

Find out how Waratek’s award-winning application security platform can improve the security of your new and legacy applications and platforms with no false positives, code changes or slowing your application.

Topics:
asp.net ,authorization ,.net ,security ,web application security

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}