Monday, 20 July 2015

Create a Custom ViewResult Return type to return a View in MVC application

In this post we are going to see how to create the Custom ViewResult, which can return the view of corresponding action for a controller.

First we have to derive a class from ViewResultBase from which we can create a custom viewResult.


    public class CustomViewResult:ViewResultBase
    {
        private string _master;
        public string Master
        {
            set { _master = value; }
            get { return this._master ?? string.Empty; }
        }

        protected override ViewEngineResult FindView(ControllerContext context)
        {
            ViewEngineResult _viewEngine = base.ViewEngineCollection.FindView(context,      
                                           ViewName, Master);
            if (_viewEngine.View != null)
                return _viewEngine;

            StringBuilder builder = new StringBuilder();

            foreach (var item in _viewEngine.SearchedLocations)
            {
                builder.Append(Environment.NewLine);
                builder.Append(item);
            }

            throw new                
            InvalidOperationException(string.Format(CultureInfo.CurrentCulture,ErrorData,
                     new []{base.ViewName,builder.ToString()}));
        }

        public string ErrorData {
            get
            {
                return "{0} ~ View not found in the following Locations {1}";
            }
        }
    }


Now create a class which is derived from the controller class, where we have to specify the wrapper method to create a instance for CustomView along with some overload methods.

   public class CustomController:Controller
   {
        protected internal CustomViewResult CustomView() {           
            return this.CustomView(null, null, null);
        }

        protected internal CustomViewResult CustomView(string viewname) {
            return this.CustomView(viewname, null, null);
        }

        protected internal CustomViewResult CustomView(string viewname, object model) {
            return this.CustomView(viewname, null, model);
        }

        protected internal virtual CustomViewResult CustomView(string viewname,string  
                                                                master,object model)
        {

            if (model != null)
                base.ViewData.Model = model;

            return new CustomViewResult() {
              ViewName = viewname,
              Master = master,
              TempData = base.TempData,
              ViewData = base.ViewData,
              ViewEngineCollection = base.ViewEngineCollection
            };
       
        }
    }

After this two class creations, now derive the controller class from CustomController, In my sample application controller name is HomeController

For example:

    public class HomeController : CustomController
    {
        public ActionResult Index()
        {
            return CustomView();
        }
    }



When we invoke the HomeController Index action, instead of View our CustomView is executed and returned the view to the client Browser.





After Button click 



For Example if we pass a view name in the custom view it will render, but if we pass a wrong view name, then the error message that we mentioned will be shown 

For example : we are passing the view name as SampleView , but it not exists, Let we see what is the output.




 we are printing the searched location where viewEngine Searched.

From this post you can learn how to create a custom ViewResult  which can return a generated view to the users.

Sunday, 19 July 2015

Avoid the CSRF attacks by implement the Antiforgery Token in MVC Web API call while using Angular JS

In this post we are going to see what is CSRF attacks and how we can avoid this kind of attacks in WEB API calls using AntiForgery token implementation inside web applications developed using a Angualr JS and Asp.Net MVC.

Cross Site Request Forgery CSRF is an attack where a unknown site sends a request to another site which is already logged in.

Consider an Example
1. Launch a Website
2. Login the Website , now the session id or authcookie is maintained in the client browser.
3. Next launch a another website which have the malicious code like below

<form action="http://facetrack.com/api/account" method="POST">
    <input type="text" name="Id" value="1" />
     <input type="hidden" name="name" value="Rajesh" />
    <input type="submit" value="Submit"  />
</form>


4. Above code call the website which is already login with the auth cookie, now the call is really sent from the another site, i.e Cross site Request Forgery by using the Authcookie or session id from browser.

Now we see how to implement a AntiForgery Token in WebApi calls using Angular js.
Steps
1. Create a Extn class

    public static class RequestHelperExtn
    {
        public static string GetHeaderToken(this HtmlHelper helper) {
            string requestToken = RequestHeaderToken();
            return  string.Format("request-header-token={0}", requestToken);
        }

        public static string RequestHeaderToken()
        {
            string cookie, form;
            AntiForgery.GetTokens(null, out cookie, out form);
            return cookie + "~" + form;
        }

        public static Tuple<string, string> ParseTokens(string token)
        {
            if (!string.IsNullOrWhiteSpace(token))
            {
                var tokens = token.Split('~');
                if(token.Length > 1)
                return Tuple.Create<string, string>(tokens[0].Trim(), tokens[1].Trim());
            }                       
            return Tuple.Create<string, string>("", "");
        }


    }

2.  Create a ActionFilterAttribute for check the AntiForgery token before the execution of method.
   
   public class AntiForgeryTokenValidateAttribute:ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            string cookie=string.Empty;
            string form = string.Empty;
            Tuple<string, string> parsedtoken = 
                  Tuple.Create<string, string>(string.Empty, string.Empty);

            IEnumerable<string> tokenheaders;
            if (actionContext.Request.Headers.TryGetValues("requestToken", out tokenheaders))             {
                if (tokenheaders.Count() > 0)
                     parsedtoken = RequestHelperExtn.ParseTokens(tokenheaders.First());
                cookie = parsedtoken.Item1;
                form = parsedtoken.Item2;
            }

            AntiForgery.Validate(cookie, form);
            base.OnActionExecuting(actionContext);

        }

    }


3. Create a Angular js directive which is used to add the Antiforgery Token in Headers of Http Call.

app.directive('requestHeaderToken', ['$http',function ($http) {

    return {
        restrict: 'A',
        scope: {
            requestHeaderToken:'@'
        },
        link:function(scope,elem,attrs){
            $http.defaults.headers.common['requestToken'] = scope.requestHeaderToken;
        }

    }


}]);


4. Place the action attribute over the http method in the Web API calls.

    public class ValuesController : ApiController
    {
        // GET api/values
        [AntiForgeryTokenValidate]
        public IEnumerable<string> Get()
        {
            return new string[] { "Rajesh G", "Suresh G" };
        }


        [AntiForgeryTokenValidate]
        // GET api/values/5
        public CustomJsonResult Get(int id)
        {
           
            return new CustomJsonResult() {
                Content = new { data = new[] { "India", "SriLanka", "Japan" }                                }                
            };
        }


        [AntiForgeryTokenValidate]
        //GET api/values
        public HttpResponseMessage Post([FromBody]string result)
        {
            JToken json = JObject.Parse("{'Id':1,'Name':'Rajesh'}");
            return new HttpResponseMessage() {
                Content = new JsonContentResponse(json)
            };
        }

   
        // PUT api/values/5
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/values/5
        public void Delete(int id)
        {
        }

    }

5.  First we invoke the client HTML with out place the AntiForgery Token

HTML:
**********
<div id="body" ng-app="app">  
    <section class="featured">
        <div ng-controller="AppController" style="padding-left:100px">
            <div>               
                <br />
                <br />
                <button ng-click="GetValues()"> Get Values with Antiforgery                      
                   Token</button>

                <div style="top:10px">
                    <div style="margin-top:30px"><b>Employees List</b>
                    </div>
                   <ul style="list-style:none">
                        <li ng-repeat="item in collections">{{item}}</li>
                    </ul>
                </div>
            </div>
            <br />
            <div style="width:500px">
                <div style="float:left">
                    <button ng-click="GetValuesByID()"> Get Valuesby Id with Antiforgery
                       Token</button>
                </div>
                <div style="float:right">
                    <button ng-click="PostValues()">Get Json Data</button>
                </div>
            </div>
            <div style="width:500px">
                <div style="height:200px;float:left">
                    <br />                   
                    <div><b>CustomJsonResult</b>
                        {{Data.Content}}
                    </div><br />
                    <b>Countries</b>
                    <br />                   
                    <ul style="list-style:none">
                        <li ng-repeat="item in Data.Content.data">{{item}}</li>
                    </ul>
                    <b></b>
                </div>
                <div style="float:right">
                    <br />
                    <b>JsonContent</b>
                    <table>
                        <tr><td>ID :</td><td>{{empdata.Id}}</td></tr>
                        <tr><td>Name :</td><td>{{empdata.Name}}</td></tr>
                    </table>
                </div>
            </div>
            <br />
            <br />
        </div>
    </section>
</div>


Angular App.Js
********************
var app = angular.module('app', []);


app.factory('DBContext', ['$http', function ($http) {

    return {
        GetValues: GetValues,
        GetValuesByID: GetValuesByID,
        PostValues: PostValues
    };

   
    function GetValues () {
        return $http({
            url: 'api/Values',
            method: 'get'
        });
    };

    function GetValuesByID(){
        return $http({
            url: 'api/Values/2',
            method: 'get'           
        });
    };

    function PostValues() {
        return $http({
            url: 'api/Values',
            method: 'POST',
            data: {
                result: 'sample data'
            }

        });
    };

}]);

app.controller('AppController', ['$scope', 'DBContext', function ($scope, DBContext) {

    $scope.Value = "Rajesh";
    $scope.collections = [];
    $scope.Data = '';
    $scope.empdata = {};
    $scope.GetValues = function () {

        DBContext.GetValues().then(function (data) {
            var result = data.data || data || [];
            $scope.collections = result;
        }, function () { });

    }

    $scope.GetValuesByID = function () {
        DBContext.GetValuesByID().then(function (data) {
            $scope.Data = data.data;
        }, function (error) {
            console.log(error);
        });
    }

    $scope.PostValues = function () {


        DBContext.PostValues().then(function (result) {
            $scope.empdata = result.data;
        }, function (error) {
            console.log("Error");
            console.log(error);
        })

    }


}]);


Output:
*********
Now invoke any one of button click with out  AntiforgeryToken attribute we will get an error like below in console, because i logged the error in browser console.








6. Now place the AntiForgery Token in the Client Html it is an angular attribute place by an HtmlHelper class 
@Html.GetHeaderToken()

Example to place inside a tag  
<div  @Html.GetHeaderToken()>    

Now we placed that  HtmlHelper inside a div tag which is present after the ng-controller defined.

<div ng-controller="AppController" style="padding-left:100px">
     <div  @Html.GetHeaderToken()>               
       <br /> 
</div>
</div>                     

After placing the Tag

Html View in Client Browser Have a token









Web Api Request Call have the AntiForgery Token in the Header









Output:
*********


From this Post you can understand how to implement a AntiForgery Token in Web API Calls in ASP.Net MVC using Angular JS