Skip to content
prashant93 edited this page Oct 3, 2016 · 33 revisions

Authorization framework provides the flexibility to authorize user/groups.

Nearly every application deals with data and resources that need to be protected. Implementing secure authentication and authorization is therefore an essential requirement in most cases. While historically the solution to that problem has been either Windows authentication or username/password, this might not hold true anymore. In the distributed and mobile application landscape, passwords have become an anti-pattern, and single sign-on, security token services and federation are the prevalent technologies to achieve a seamless security experience for your users.

Authorization Framework supports WebAPI and WCF authorization.

1. APP and API in same Project

This walkthrough will help to integrate Authorization Framework in application. The walkthrough is split in 2 parts:

  • Authentication.
  • Make API calls from the application.

Part 1 - Authentication

In the first part we will create a simple MVC application and add authentication via ADFS to it. Later, we will have a closer look on authorization and integration of Authorization Framework.

  • Create the web application In Visual Studio 2015, create a standard MVC application and set authentication to “Work and School Accounts”.

Create MVC App

Add metadata url

You can switch the project now to SSL using the properties window:

SSL

  • Adding Authorization Framework

To add Authorization Framework to project, add the below libraries:

  1. Merilent.Authorization.dll
  2. Entity Framework
  3. Merilent.Logger
  4. System.IdentityModel.Tokens.Jwt
  • Configuring Authorization Framework Application

Authorization Framework needs some information of ADFS and Application, this can be simply supplied using web.config

<connectionStrings>
  <add name="ConnectionName" connectionString="Data Source=DatabaseServer;Initial Catalog=DatabaseName;
    Integrated Security=true"providerName="System.Data.SqlClient"/>
 </connectionStrings>

<appSettings>
 <add key="ida:ADFSMetadata" value="https://AdfsServer/FederationMetadata/2007-06/FederationMetadata.xml"/>
 <add key="ida:Wtrealm" value="RelyingPartyURL"/>
</appSettings>

Adding Startup

Authorization Framework is configured in the startup class. Here we provide information about the clients, users, scopes, the signing certificate and some other configuration options.

Go to App_Start folder and select Startup.Auth.cs and add the below code for saving user token in session

using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.WsFederation;
using Owin;
using System.Configuration;

namespace ClaimeAwareAPP_API
{
    public partial class Startup
    {
      private static string realm = ConfigurationManager.AppSettings["ida:Wtrealm"];
        private static string adfsMetadata = ConfigurationManager.AppSettings["ida:ADFSMetadata"];

        public void ConfigureAuth(IAppBuilder app)
        {
          app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

            app.UseCookieAuthentication(new CookieAuthenticationOptions()

            );

            app.UseWsFederationAuthentication(
                new WsFederationAuthenticationOptions
                {
                    Wtrealm = realm,
                    MetadataAddress = adfsMetadata,
                    TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters()
                    {
                        SaveSigninToken = true
                    }
                });
        }
    }
}

Adding Global configuration:

Adding Application role to user context:

using Merilent.Authorization;
using System.Configuration;
using System.Security.Claims;
using System.Threading;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;


protected void Application_PostAuthenticateRequest()
{
  
 //Adding Application Roles to user
ClaimsPrincipal currentPrincipal = ClaimsPrincipal.Current;
   
Thread.CurrentPrincipal = RoleProvider.ApplicationRoles(currentPrincipal,  ConfigurationManager.AppSettings["ida:APIName"], ConfigurationManager.ConnectionStrings["connectionstringname"].ConnectionString);
   
HttpContext.Current.User = Thread.CurrentPrincipal;
                
} 
  • Role Authorization:

Now that we have authentication and some claims, we can start adding simple authorization rules. MVC has a built-in attribute called [Authorize] to require authenticated users, you could also use this attribute to annotate role membership requirements. We don’t recommend this approach.

However, if you do choose to use [Authorize(Roles = "Admin")] be aware that sites can be thrown into an infinite redirection loop when the current user is authenticated, but does not belong to one of the roles or users you pass into the Authorize attribute.

This undesirable outcome occurs because the Authorize attribute will set the action’s result to 401 unauthorized when the user is authenticated, but not in one of the roles. That 401 result triggers a redirect to authenticate with ADFS server, which authenticates and then redirects the user back, and then the redirect loop begins.

This behavior can be overcome by overriding the Authorize attribute’s method as follows, and then use the customized authorization attribute instead of what comes with MVC.

using Merilent.Authorization;
using System;
using System.Web;
using System.Web.Http;

public class TestController : ApiController
{
   [AuthorizeUser(Roles = "Admin")]
   public string Get()
   {
          return "Authorized User";
   }
 }

Follow the above steps to include authentication and authorization in your application having API and web as single application.

  • Part 2 Make API calls from the application:

In the second part, we’ll see how you can call a protected API from the angular or ajax call application.

As Web app using angular or ajax to call API and both API and Web app are in same project, JWT token created for authenticated user exist in session.

  • Calling the API

Now that we have an JWT token of authenticated, we can include the call to the API:

  var mainApp = angular.module("app", []);
  mainApp.controller('appController', function ($scope, $http) {

    $http({ method: 'GET', 
      dataType: 'json', 
      url: 'https://localhost:44319/api/test/' })
      .success(function (response) {
          $scope.applications = response;
         })
       .error(function (error) {
          $scope.applications = error;
       })

If user is not authenticated will redirect to authentication or if not authorized will give unauthorized message.

2. Web APP to API call

This walkthrough will help to integrate Authorization Framework in MVC application.

To add Authorization Framework to the newly created project, add the following libraries:

  1. Merilent.Authorization.dll
  2. Entity Framework
  3. Merilent.Logger
  4. System.IdentityModel.Tokens.Jwt
  • Create a API service: In Visual Studio 2015, create a standard MVC API and select no authentication.

    Create MVC App

    Create MVC App

  • API service:

    Decorate your API Controller with Auhtorize Framework Authorize attirbute i.e. [AuhtorizeUser(Roles ="Admin")]

using Merilent.Authorization;
using System;
using System.Security.Claims;
using System.Threading;
using System.Web;
using System.Web.Http;

    public class ValueController : ApiController
    {
       [AuthorizeUser(Roles = "Admin")]
        public string Get()
        {
            var identity = (ClaimsPrincipal)Thread.CurrentPrincipal;

             var userName = identity.FindFirst(ClaimTypes.Name).Value;

             return userName;        
         }
     }
  • Configuring Authorization Framework Application

Authorization Framework needs some information about ADFS and Application, this can be simply supplied using web.config of Application:

On API

<connectionStrings>
  <add name="ConnectionName" connectionString="DataBaseName"providerName="System.Data.SqlClient"/>
</connectionStrings>

<appSettings>
  <add key="ida:ADFSMetadata" value="https://AdfsServer/FederationMetadata/2007-06/FederationMetadata.xml"/>
  <add key="ida:Wtrealm" value="RelyingPartyURL"/>
  <add key="ida:APIName" value="ApiName" />
</appSettings>

On Client

 <connectionStrings>
  <add name="ConnectionName" connectionString="DataBaseName"providerName="System.Data.SqlClient"/>
 </connectionStrings>

<appSettings>
  <add key="ida:ADFSMetadata" value="https://AdfsServer/FederationMetadata/2007-06/FederationMetadata.xml"/>
  <add key="ida:APIName" value="ApiName" />
</appSetting

ApiName configuration on Client is used to get Secret configured in Database. So, the generated token is only be used by the Api configured on client this makes sure that other api cannot use the generated token.

  • Adding Global configuration:

Add global Message Handlers for Validation of JWT token on API.

using Merilent.Authorization;
using System.Configuration;

    public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
           GlobalConfiguration.Configuration.MessageHandlers.Add(newTokenValidationHandler(
                      ConfigurationManager.ConnectionStrings["ConnectionstringName"].ConnectionString,
                      ConfigurationManager.AppSettings["ida:APIName"],
                      ConfigurationManager.AppSettings["ida:ADFSMetadata"]));

        }
    }
  • Make API Call: Now call API service from Client.
using Merilent.Authorization;
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Http;

    [AuthorizeUser(Roles = "Admin")]
   public class TestController : ApiController
   { 
       public string Get()
       {
		//Getting Token from Client                         
         var token = TokenGenerationHandler.GetToken(
                       ConfigurationManager.ConnectionStrings["AuthorizationConnection"].ConnectionString,
                       ConfigurationManager.AppSettings["ida:APIName"],
                       ConfigurationManager.AppSettings["ida:ADFSMetadata"]);

           HttpClient client = new HttpClient();

           client.BaseAddress = new Uri("https://localhost:44377/");
           client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
           client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",token );

           HttpResponseMessage response = client.GetAsync("api/value/").Result;
           if (response.IsSuccessStatusCode)
           {
               return response.Content.ReadAsAsync<string>().Result;
           }

           return "false";    
     }
   }

3. Wcf Client to Wcf Service

This walkthrough will help to integrate Authorization Framework in WCF service application.

To add Authorization Framework to the newly created project, add the following libraries:

1. Merilent.Authorization.dll
	2. Entity Framework
	3. Merilent.Logger
	4. System.IdentityModel.Tokens.Jwt
  • Create a WCF service:

    In Visual Studio 2015, create a standard WCF service application.

Create WCF service

  • WCF service:

  • Configuring Authorization Framework Application

Authorization Framework needs some information about ADFS and Application, this can be simply supplied using web.config of WCF service and WCF client:

WCF Service:

<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true">
   <behaviors>
      <serviceBehaviors>
          <bearerTokenRequired connectionString ="Data Source=DatabaseServer;Initial Catalog=DataBaseName;
                Integrated Security=true" providerName="System.Data.SqlClient" appName="ServiceName" 
                metadataEndpoint="https://ADFSServerName/FederationMetadata/2007-06/FederationMetadata.xml"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <extensions>
      <behaviorExtensions>
      <add name="bearerTokenRequired" type="Merilent.Authorization.BearerTokenExtensionElement, Merilent.Authorization" />
      </behaviorExtensions>
    </extensions>
</system.serviceModel>

WCF Client:

<connectionStrings>
  <add name="ConnectionName" connectionString="DataBaseName"providerName="System.Data.SqlClient"/>
 </connectionStrings>

  <appSettings>
    <add key="ida:ADFSMetadata" value="https://AdfsServer/FederationMetadata/2007-06/FederationMetadata.xml"/>
    <add key="ida:Wtrealm" value="RelyingPartyURL"/>
  </appSettings>

 <behaviors>
      <endpointBehaviors>
        <behavior>
          <customInspector connectionString ="Data Source=DatabaseServer;Initial Cata-log=DataBaseName;
                  Integrated Security=true" providerName="System.Data.SqlClient" appName="WCFserviceName"
                metadataEndpoint="https://ADfsServer/FederationMetadata/2007-06/FederationMetadata.xml" />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <extensions>
      <behaviorExtensions>
       <add name="customInspector" type="Merilent.Authorization.ClientBehaviorExtensionElement, Merilent.Authorization" />
      </behaviorExtensions>
    </extensions>

Authorize user on WCF service:

using System.Security.Permissions;
using System.Linq;
using System.Security.Claims;
using System.Threading;
using System.Security;

public class Service : IService
{
    [PrincipalPermission(SecurityAction.Demand, Role = "Admin")]    
     public string GetData()
     {
             var user = HttpContext.Current.User.Identity;

             var identity = (ClaimsPrincipal)Thread.CurrentPrincipal;
           
             var name = identity.Claims
                                .Where(c => c.Type == ClaimTypes.Name)
                                .Select(c => c.Value).First();

                return string.Format("You Name is: {0}", name);
      }
}
  • Make WCF service Call from WCF client:
    public class WCFServiceCaller
    {
       public string GetServiceData()
        {
	  Service1Client client = new Service1Client();
          String s = client.GetData();
          return s;
        }
    }

Roles Configuration

Now let’s go through Application roles configuration

  • Table tblApplication:

In this configure your application and service using Authorization framework.

Create Applicaitontable

  • Table tblGroup:

In this configure the AD group for assigning Roles.

Create Grouptable

  • Table tblUser:

    In this configure the AD user for assigning Roles.

    Create Usertable

  • Table tblRole:

    In this configure the all Roles for Application or service configured in tblApplication.

    Create Roletable

  • Table tblPermission:

In this configure the all Roles for user or user Group for corresponding Application.

Create Permissiontable

Relation of all Tables:

Create RelationDiagram