1
votes

I'm using [WebAPI Basic Authentication Authorization Filter] to authorize users on consuming my simple web api data service.

Question is: everything work on localhost but when I publish my service to the web (http://www.mywebsite.com) client app always gets "Unauthorize" response.

This line is all I change (on client side) when switching from localhost to the web

//client.BaseAddress = new Uri("http://localhost:11992/"); // on localhost work
  client.BaseAddress = new Uri("http://mywebsite.com/"); // returns 401 Unauthorized

Tried with adding machine key using remote IIS manager but same thing happens.

enter image description here

reference this machine key in system.web (web.config) enter image description here

and authentication mode on IIS is as follows

enter image description here

Still doesnt work. Obviously I'm missing something here.

UPDATE I'm extending basic auth. filter which I later apply on my controller action (the one I access from client side)

[MyBasicAuthenticationFilter]
public class DataController : RavenController { ... }

and inside this custom auth. filter there is hardcoded username and pass

public class MyBasicAuthenticationFilter : BasicAuthenticationFilter
{

    public MyBasicAuthenticationFilter()
    { }

    public MyBasicAuthenticationFilter(bool active)
        : base(active)
    { }


    protected override bool OnAuthorizeUser(string username, string password, HttpActionContext actionContext)
    {
        if (username == "myuser" && password == "mypass")
            return true;
        else
            return false;
    }
}

and from client side (wpf client)

client.BaseAddress = new Uri("http://mywebsite.com/");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
                Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(
                string.Format("{0}:{1}", "myuser", "mypass"))));

I'm confused because same code work fine on localhost but when I publish code and change this client.BaseAddress to my actual website url it returns 401 error.

1
Can you expand upon you code example please to demonstrate how you are attempting to set the user credentials? 401 unauthorised means that no credentials were provided or the ones provided are not valid. Does the user account(s) you are authenticating with exist on the server? Note: machine key is not used by basic authentication.Adrian Sanguineti
@Adrian, question is updateduser1765862
What is the "WebAPI Basic Authentication Authorization Filter" you're extending? The link in the question goes to the machine key image. Is this the correct correct link that is meant to be there: weblog.west-wind.com/posts/2013/Apr/18/…Adrian Sanguineti
yes, that's correct link.user1765862
What kind of debugging of this issue have you done. Have you looked at adding any logging into your server side code? (I assume you can't remote debug). In particular within the ParseAuthorizationHeader method of the BasicAuthenticationFilter class. My best guess on the possible cause right now is that the Default Encoding on the server you have deployed to is not the same as your local dev.Adrian Sanguineti

1 Answers

1
votes

The BasicAuthenticationFilter class given Rick Strahl's Web Log uses the System's default encoding to extract the user credentials from the authorization header. As per the MSDN documentation for the Encoding.Default property:

Different computers can use different encodings as the default, and the default encoding can even change on a single computer. Therefore, data streamed from one computer to another or even retrieved at different times on the same computer might be translated incorrectly. In addition, the encoding returned by the Default property uses best-fit fallback to map unsupported characters to characters supported by the code page. For these two reasons, using the default encoding is generally not recommended. To ensure that encoded bytes are decoded properly, you should use a Unicode encoding, such as UTF8Encoding or UnicodeEncoding, with a preamble. Another option is to use a higher-level protocol to ensure that the same format is used for encoding and decoding.

Based on the information provided, this is the mostly likely line of code which can potentially give different results based on the configuration of the server your code is deployed to.

I would therefore consider replacing the following line in the ParseAuthorizationHeader method of the BasicAuthenticationFilter class:

authHeader = Encoding.Default.GetString(Convert.FromBase64String(authHeader));

with the following code:

Encoding iso88591 = Encoding.GetEncoding("iso-8859-1");
authHeader = iso88591.GetString(Convert.FromBase64String(authHeader));

iso-8859-1 will give you best compatibility with all clients that send basic authentication header. See the following StackOverflow question on the recommend encoding to use when doing HTTP Basic Authentication: What encoding should I use for HTTP Basic Authentication?

Alternatively if you're the only one who will be calling the API from your WCF client, then just make sure you're encoding the username and password in the same character code as the server will be decoding it in.