Search This Blog

Thursday, March 24, 2016

MVC Active Directory Attribute Based Authorization with example


MVC Active Directory Attribute Based Authorization with example


Active Directory based authorization in .NET is fairly easy. Just throw an attribute on a controller as follows:

[Authorize (Roles="AdGroup")]
public class HomeController : Controller 

Sometimes though you do not want to hard code a role in an attribute as you may want to add or remove roles at will. You may also want to change the roles based on whether you are in production or not. I like to keep my Active Directory roles either in a database or a web.config file so that others can change authorization on the fly. In order to have greater control over your authorization roles you need to extend the AuthorizeAttribute and override AuthorizationCore. You also need to override HandleUnauthorizedRequest in order to have a custom redirect page.
Web.Config
<appSettings>
  <add key="Authorization.site" value="Domain\GeneralGroupName"/>
  <add key="AdminGroup" value="Domain\AdminGroupName"/>
</appSettings>
 
<system.web>
  <identity impersonate="false"/>
  <roleManager enabled="true" defaultProvider="AspNetWindowsTokenRoleProvider">   </roleManager>
  <authentication mode="Windows"></authentication>
  <authorization>
    <allow roles="Domain\GeneralGroupName"/>
    <allow roles="Domain\AdminGroupName"/>
    <deny users="*"/>
  </authorization>
</system.web>
 
 
Role based Authorization code

/// <summary>
    /// Redirects to the unauthorized page.
    /// </summary>
    public class AuthorizeSiteRedirect : AuthorizeAttribute
    {
        /// <summary>
        /// Authorization based on roles in web.config.
        /// </summary>
        /// <param name="httpContext" />The http context
        /// <returns>Whether a user is authorized.</returns>
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            //// In this example we use a web.config key.
            //// <add key="Authorization.site" value="Your comma separated Ad Group List"/>
            var roles = ConfigurationManager.AppSettings["Authorization.Site"];
return roles.Split(',').ToList().Any(role => httpContext.User.IsInRole(role.Trim()));
        }

        /// <summary>
        /// Redirects an unauthorized request to the unauthorized page.
        /// </summary>
        /// <param name="filterContext" />The filter context
       protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            filterContext.Result = new RedirectResult("~/Unauthorized");
        }
    }
You can now add more authorization levels for example an Admin level.

        /// <summary>
    /// Redirects to the unauthorized page.
    /// </summary>
    public class AuthorizeAdminRedirect : AuthorizeSiteRedirect
    {
        /// <summary>
        /// Authorizes a user based on active directory groups.
        /// </summary>
        /// <param name="httpContext" />The http context</param>
        /// <returns>Whether a user is authorized.</returns>
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            var roles = ConfigurationManager.AppSettings["AdminGroup"]; 
           return roles.Split(',').ToList().Any(role =>  httpContext.User.IsInRole(role.Trim()));
        }
    }
Now all you have to do is add an attribute to your controller and you are done:
[AuthorizeSiteRedirect]
public class HomeController : Controller 

    /// <summary>
    /// Administration page for site settings.
    /// </summary>
[AuthorizeAdminRedirect]
public class AdminController : Controller
 
Please be aware that when you store you active directory groups in a location like your config file you need to be sure 
to trim whitespace from your group name. Otherwise httpContext.User.IsInRole will not work accurately. For example if User1 is in group Group1 then User.IsInRole(" Group1") will return false however User.IsInRole("Group1") will return true.
 
If your website is throwing unauthorized access like below:
Access is denied. Description: An error occurred while accessing the resources required to serve this request. The server may not be configured for access to the requested URL.

Error message 401.2.: Unauthorized: Logon failed due to server configuration.  Verify that you have permission to view this directory or page based on the credentials you supplied and the authentication methods enabled on the Web server.  Contact the Web server's administrator for additional assistance.
Then check your project properties like below. Generally you will get this issue with new web application created with VS 2013.
 
Visual Studio 2013  Ã  New Web Application à By default Windows Authentication is disabled and 
Anonymous is Enabled à Perform changes like below.
 
 

Thursday, March 17, 2016

MVC Handling multiple submit buttons in single view


MVC: Handling Multiple button submission from one view

While developing any web applications we use to design lot more forms. Most of the times a form perform a single action, posting data to some controller. There is no necessity that each of the form will contain only a single submit button. Sometimes, we may need a form which will contain multiple submit buttons.  As in the following case
 

<h2>SignUp</h2>

@using (Html.BeginForm("PostData","Home", FormMethod.Post))

{

    @Html.AntiForgeryToken()

    <div>

        <fieldset>

            <legend>Account Information</legend>

            <p>

                <label for="username">Username:</label>

                @Html.TextBox("username")

            </p>

            <p>

                <label for="email">Email:</label>

                @Html.TextBox("email")               

            </p>

            <p>

                <label for="password">Password:</label>

                @Html.TextBox("password")

            </p>

            <p>

                <label for="confirmPassword">Confirm Password:</label>

                @Html.TextBox("confirmPassword")

            </p>

            <p>

                <input type="submit" name="btnRegister" id="btnRegister" value="register" />

                <input type="submit" name="btnCancel" id="btnCancel" value="Cancel" />                           

            </p>

        </fieldset>

    </div>

}

So in this case, our form will be posting data to a single action PostData but it contains 2 different submit button.  So to handle this scenario, we need to code something like this in our controller.
// handling multiple buttons post by using if else conditions
        [HttpPost]
        public ActionResult PostData(string btnRegister, string btnCancel)
        {
            string buttonName = btnRegister ?? btnCancel;

            if (!string.IsNullOrEmpty(btnRegister))
                            //write code related to Register           
            }
            else if (!string.IsNullOrEmpty(btnCancel))
            {                //write code related to Cancel           
             }
            return Content("button name: " + buttonName);       
        }

Also this looks very simple when we have a simple Action, think how about doing this on a form of 10 fields & 4 buttons.

How if I am able to specify the name of the button near the action method wherein I will specify the name of the button on which that action needs to be invoked.  We can achieve this in Asp.Net MVC by using the ActionMethodSelectorAttribute attribute. Here is a code snippet to show the use of the attribute.

public class AcceptParameterAttribute : ActionMethodSelectorAttribute
    {
        public string Name { get; set; }
        public string Value { get; set; }

        public override bool IsValidForRequest(ControllerContext controllerContext,                                     System.Reflection.MethodInfo methodInfo)
        {
           var req = controllerContext.RequestContext.HttpContext.Request;
            return req[this.Name] == this.Value;
        }
    }

The ActionMethodSelectorAttribute is executed before the Action is executed, so we here we can check which button is clicked while submitting the form using the Form NameValueCollection object on the IsValidForRequest event of the ActionMethodSelectorAttribute.

This attribute will also help preventing the JavaScript attacks as this will only accept the values submitted by the specific submit button.

public class HomeController : Controller    {
// handling multiple buttons post by using ActionMethodSelectorAttribute
        [HttpPost]
        [ActionName("PostData")]
        [AcceptParameter(Name = "btnRegister", Value = "register")]
        public ActionResult PostbtnRegister(string username, string email, string password, string confirmPassword)
        {
            return Content("you clicked reset" + username + email + password + confirmPassword);
        }

        [HttpPost]
        [ActionName("PostData")]
        [AcceptParameter(Name = "btnCancel", Value = "Cancel")]
        public ActionResult PostbtnCancel(string username, string email, string password,                                 string confirmPassword)
        {
            return Content("you clicked Cancel" + username + email + password +                                                      confirmPassword);
        }}

Popular Posts