Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WEB API - Authorize at controller or action level (no authentication)

I have an existing API that has No Authentication. It`s a public Web API which several clients use by making simple requests.

Now, there is the need to authorize access to a certain method.

Is there any way to do this, keeping the rest of the controllers and respective methods "open" for the clients that already use this Web API?

How can i identify if the request has permissions to access this "protected" method?

like image 667
JCruz Avatar asked Aug 03 '16 18:08

JCruz


1 Answers

What you'll need to do is add an [Authorize] attribute to the methods you want to protect optionally using the overload that accepts one or more role names that the calling user must be in.

Then what you'll have to implement is a way to ensure that authentication data of the caller is transformed into a Principal object. Setting the Principal is generally something you don't do yourself, but instead have the framework do for you.

If you do want to provide your own interface, you can using an authentication filter implementing the System.Web.Http.Filters.IAuthenticationFilter interface.

So what you'll get is this:

[MyAuthentication]
[Authorize]
public SomeClass MyProtectedMethod() {
    return new SomeClass();
}

And then implement the MyAuthentication attribute. Below is an example, the important thing is that you use the context of the incoming request and end up setting the context.Principal property with a new Principal

public class MyAuthentication : ActionFilterAttribute, System.Web.Http.Filters.IAuthenticationFilter {

    public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
    {
        // 1. Look for credentials in the request.
        HttpRequestMessage request = context.Request;
        AuthenticationHeaderValue authorization = request.Headers.Authorization;

        // 2. If there are no credentials, do nothing.
        if (authorization == null)
        {
            return;
        }

        // 3. If there are credentials but the filter does not recognize the 
        //    authentication scheme, do nothing.
        if (authorization.Scheme != "Basic")
        {
            return;
        }

        // 4. If there are credentials that the filter understands, try to validate them.
        // 5. If the credentials are bad, set the error result.
        if (String.IsNullOrEmpty(authorization.Parameter))
        {
            context.ErrorResult = new AuthenticationFailureResult("Missing credentials", request);
            return;
        }

        Tuple<string, string> userNameAndPasword = ExtractUserNameAndPassword(authorization.Parameter);
        if (userNameAndPasword == null)
        {
            context.ErrorResult = new AuthenticationFailureResult("Invalid credentials", request);
        }

        string userName = userNameAndPasword.Item1;
        string password = userNameAndPasword.Item2;

        IPrincipal principal = await AuthenticateAsync(userName, password, cancellationToken);
        if (principal == null)
        {
            context.ErrorResult = new AuthenticationFailureResult("Invalid username or password", request);
        }

        // 6. If the credentials are valid, set principal.
        else
        {
            context.Principal = principal;
        }

    }


    ... other interface methods here
}

I hope this helps you get on the right track. For more information check this post: http://www.asp.net/web-api/overview/security/authentication-filters

like image 142
Robba Avatar answered Nov 15 '22 18:11

Robba