Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

asp mvc 3 ActionFilter for basic authentication

I have an ASP MVC3 restful service that uses basic authentication. After searching stack overflow, I created the following code.

public class BasicAuthentication : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var req = filterContext.HttpContext.Request;
        if (String.IsNullOrEmpty(req.Headers["Authorization"]))
        {
            filterContext.Result = new HttpNotFoundResult();
        }
        else
        {
            var credentials = System.Text.ASCIIEncoding.ASCII
                        .GetString(Convert.FromBase64String(req.Headers["Authorization"].Substring(6)))
                        .Split(':');
            var user = new { Name = credentials[0], Password = credentials[1] };
            if(!(user.Name == "username" && user.Password == "passwords"))
            {
                filterContext.Result = new HttpNotFoundResult();
            }
        }
    }
}

1) Is an ActionFilterAttribute the best way to do this?

2) Is setting filterContext.Result the correct way to deny access to the controller method?

3) Is there anything I'm doing wrong?

Thanks.

-Nick

like image 420
Nikhil Avatar asked Feb 22 '12 17:02

Nikhil


People also ask

How do I create an authentication filter?

To create a custom authentication filter in ASP.NET MVC, we need to create a class by implementing the IAuthenticationFilter Interface. This IAuthenticationFilter interface has 2 methods. Open Visual Studio 2015 or an editor of your choice and create a new project.

How will you implement Basic Authentication in ASP Net Web API?

In IIS Manager, go to Features View, select Authentication, and enable Basic authentication. In your Web API project, add the [Authorize] attribute for any controller actions that need authentication. A client authenticates itself by setting the Authorization header in the request.

How do you pass Basic Authentication in header .NET core?

Basic Authentication works by adding an Authorization header into a HTTP request. The value of the Authorization header must be Basic, followed by a space, followed by the username and password separated by a colon. The username and password are encoded using Base64.


2 Answers

1) Is an ActionFilterAttribute the best way to do this?
I think so. This approach mirrors the implementation of the built in Authorize attribute.

2) Is setting filterContext.Result the correct way to deny access to the controller method?
Yes. Thats whats it there for. (1)

3) Is there anything I'm doing wrong?

  • You assume that the content of the Authorization header is in the correct format and is correctly encoded.
  • You assume that the request is for basic authenication and not any other authentication scheme.
  • I would prefer to use HttpUnauthorizedResult() to send a http 401 error instead of a http 404 error via HttpNotFoundResult().

Below in my implementation of your code (which I'm sure has its issues too).

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        try
        {
            if (String.IsNullOrEmpty(filterContext.HttpContext.Request.Headers["Authorization"]))
            {
                filterContext.Result = new HttpUnauthorizedResult();
            }
            else
            {
                if (filterContext.HttpContext.Request.Headers["Authorization"].StartsWith("Basic ", StringComparison.InvariantCultureIgnoreCase))
                {
                    string[] credentials = ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(filterContext.HttpContext.Request.Headers["Authorization"].Substring(6))).Split(':');

                    if (credentials.Length == 2)
                    {
                        if (String.IsNullOrEmpty(credentials[0]))
                        {
                            filterContext.Result = new HttpUnauthorizedResult();
                        }
                        else if (!(credentials[0] == "username" && credentials[1] == "passwords"))
                        {
                            filterContext.Result = new HttpUnauthorizedResult();
                        }
                    }
                    else
                    {
                        filterContext.Result = new HttpUnauthorizedResult();
                    }
                }
                else
                {
                    filterContext.Result = new HttpUnauthorizedResult();
                }
            }

            base.OnActionExecuting(filterContext);
        }
        catch
        {
            filterContext.Result = new HttpUnauthorizedResult();
        }
    }

Notes

  • I haven't included illegal character checks for username and password.
  • I couldn't settle on how to implement exception handling so I have gone with simplicity.

References

(1) http://msdn.microsoft.com/en-us/magazine/gg232768.aspx

like image 159
Adrian Toman Avatar answered Nov 15 '22 10:11

Adrian Toman


Refactored version of Adrian's

public class BasicAuthenticationAttribute : ActionFilterAttribute
{
    private static readonly string AuthorizationHeader = "Authorization";
    private static readonly string BasicHeader = "Basic ";
    private static readonly string Username = "username";
    private static readonly string Password = "password";
    private static readonly char[] Separator = ":".ToCharArray();

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        try
        {
            if (!Authenticated(filterContext.HttpContext.Request))
                filterContext.Result = new HttpUnauthorizedResult();

            base.OnActionExecuting(filterContext);
        }
        catch
        {
            filterContext.Result = new HttpUnauthorizedResult();
        }
    }

    private bool Authenticated(HttpRequestBase httpRequestBase)
    {
        bool authenticated = false;

        if (String.IsNullOrEmpty(httpRequestBase.Headers[AuthorizationHeader]) == false &&
            httpRequestBase.Headers[AuthorizationHeader].StartsWith(BasicHeader, StringComparison.InvariantCultureIgnoreCase))
        {
            string[] credentials = Encoding.ASCII.GetString(Convert.FromBase64String(
                httpRequestBase.Headers[AuthorizationHeader].Substring(BasicHeader.Length))).Split(Separator);

            if (credentials.Length == 2 && credentials[0] == Username && credentials[1] == Password)
            {
                authenticated = true;
            }
        }

        return authenticated;
    }
}
like image 44
humblesticker Avatar answered Nov 15 '22 10:11

humblesticker