51
votes

I am playing with an MVC4 application and using WebAPI for fetching/sending all my data. In a controller I am using an HttpClient request to get the data and all is working fine. The issue I am facing is that when Windows authentication is enabled in the project, the web API calls are returning a 401 Unauthorized error.

the code in my controller that does the calling is:

using (var client = new HttpClient())
{
    var invoiceDetailUrl = BASE_URL + Url.HttpRouteUrl(
        "DefaultApi",
        new { controller = "InvoiceDetails", id = id }
     );

     var result = client.GetAsync(invoiceDetailUrl).Result; 

 }

Windows authentication has to be on for the site, but not necessarily the Web API controllers. I have tried excluding the API controllers in the web.config like below:

<location path="api">
        <system.web>
            <authorization>
                <allow users="*"/>
        </authorization>
    </system.web>
</location>

but the additions to the web.config did nothing.

Any suggestions?

3
You ever find a solution for this? I am looking for the same thing.Martin
yes I did, I found that you need to do this: HttpClientHandler handler = new HttpClientHandler(); handler.UseDefaultCredentials = true; using (var client = new HttpClient(handler)) { } }ncbl
@ncbl - Where and how do you add this? on the master page? would you send me sample code? (ASP.NET Intranet site using Visual Studio 2013 - .NET 4.5 Framework)Dan B

3 Answers

77
votes

Authentication

Web API assumes that authentication happens in the host. IIS uses HTTP modules for authentication. asp.net now allow you to configure via web.config any of the authentication modules built in to IIS or ASP.NET, or write your own HTTP module to perform custom authentication.

enter image description here

You can use multiple authentications at the same time, it's not a problem. In you case, you need both Windows authentication & Anonymous authentication. Windows authentication will secure your WebSite, and Anonymous authentication will open your Web Api.

Configure Authentication in IIS

Hosting on IIS Express Open the Properties pane (via F4 and not the properties of the project), and apply desired authentication Set "Anonymous Authentication" to "Disabled". Set "Windows Authentication" to "Enabled".

Hosting on IIS 7 or later In IIS Manager, open the Authentication feature in the features View. Enable/Disable desired authentication. If an authentication system is not an option (such as Windows), you'll need to install it via the Server Manager (Add Role Services).

Authorization

asp.net Authorization

In ASP.NET, there are two ways to authorize access to a given resource: File and Url authorization. I won't explain it here but you can read this article.

The important thing is that you can allow/deny users and/or groups in web.config.

The default config in Windows authentication is to allow only authentication users *****, like this :

<authorization>
<deny users="?" ></deny>
</authorization>

If you want to allow anonymous users ? under the url location "api", add this :

<location path="api">
    <system.web>
        <authorization>
            <allow users="*"/>
        </authorization>
    </system.web>
</location>

Web Api Authorization

asp.net Web Api Authorization happens later in the pipeline, closer to the controller. That lets you make more granular choices when you grant access to resources.

Web API provides a built-in authorization filter, AuthorizeAttribute. There is also an AllowAnonymousAttribute. You can use it Globally, on a Controller or on an action. By default, all actions are authorized.

Testing Api

Via Browser

Integrated Windows authentication works with any browser that supports the Negotiate authentication scheme. It's the cas for Internet Explorer and now Chrome : they will automatically provide Windows Credentials when browsing a Web Site with Windows authentication. Firefox does not support this scheme, so I often test authentication with this browser.

Via HttpClient Your HttpClient needs to provide Credentials when invoking the Web Api (like browsers). This is done by configuring an HttpClientHandler whith appropriate credentials.

//use default credentials aka Windows Credentials
HttpClientHandler handler = new HttpClientHandler()
{
    UseDefaultCredentials = true
};

//use username/password credentials
HttpClient client = new HttpClient(handler);

var handler = new HttpClientHandler {
    Credentials = new NetworkCredential(username, password)
};

var httpClient = new HttpClient(handler);

Hope this will help you.

One last important thing in you case, is that your Web Api does not allow anonymous users at all ! Because you are using Default Credentials in your HttpClientHandler, this means that your service requires Windows authentication. You don't have to configure any credentials in an open & public service.

28
votes

I came across this question while trying to do something very similar and wanted to add to the answer given above. I haven't found a lot of detailed information out there on how to do this. Just bits and piece all over the web. So hopefully this will add to what's out there.

I have an MVC4 application that has a WebAPI part to it. The MVC app needs to use Windows Auth, but the WebAPI portion needed to be anonymous and have Windows Auth turned off. While the above solution worked for ncbl, it didn't work for me because in my scenario I was not using code to handle credentials. In my scenario, I wanted a web.config or IIS based solution. I started with Cybermaxs' web.config solution and added to it. Here's what I ended up with.

<!-- Configure the virtual path api -->
<!-- This section is like a mini-web.config for the virtual path -->
<location path="api">
    <system.web>
        <authorization>
            <!-- All anonymous users access to the virtual path api -->
            <allow users="?" />
        </authorization>
    </system.web>
    <!-- Need to include the security overrides else it will inherit from the root of the application -->
    <system.webServer>
        <security>
            <authentication>
                <!-- Need to enable anonymous access and turn off Windows authentication for the virtual path -->
                <anonymousAuthentication enabled="true"/>
                <windowsAuthentication enabled="false"/>
            </authentication>
        </security>
    </system.webServer>
</location>

The key for me was to add the <system.webServer> section to the web.config so that I could override the authentication for this virtual path. I tried to do this in IIS, but since it was a virtual path, i.e. /api doesn't exist on the web server, this was not possible for me.

Note: Be aware, IIS might have a config file at a higher configuration level that is locking the <authentication> section, such as in the application.config or machine.config. An element might have the the attribute allowOverride set to false. I was getting a HTTP Error 500.19 (HRESULT: 0x80070021) at first and had to go into the application.config file to change this attribute. I found more details on this error here.

Once I had this additional section in the <location> section of my web.config I made sure to decorate my api controller with [AllowAnonymous]. Then bam...it all started to work.

This is how I have authentication and authorization setup for the root of my application.

<system.web>
  <authentication mode="Windows" />
  <authorization>
    <!-- Deny all anonymous users at the root of the application -->
    <deny users="?" />
  </authorization>
</system.web>
4
votes

This is what I needed to do:

<location path="api">
    <system.web>
        <authorization>
            <allow users="*"/>
        </authorization>
    </system.web>
</location>