I've been trying to create a relatively straightforward self-hosted RESTful service with WCF, but I wanted to add custom authentication. To that end I tried overriding the UserNamePasswordValidator
. Unfortunately, although this is being called to validate a username/password combination, if the username/password don't pass, the server returns a 403 Forbidden, rather than a 401 Unauthorized, as I'd expect. This will cause a big problem because if a user fails to authenticate the first time, they won't be prompted to enter credentials again unless they restart the browser. So, what am I doing wrong?
This is what I have so far :
(The actual ServiceContract
contains a single method which returns a string)
class Program
{
static void Main(string[] args)
{
WebServiceHost host = null;
try
{
host = new WebServiceHost(typeof (MyService));
const string uri = "http://127.0.0.1/MyService";
var wb = new WebHttpBinding
{
Security =
{
Mode = WebHttpSecurityMode.TransportCredentialOnly,
Transport = {ClientCredentialType = HttpClientCredentialType.Basic}
}
};
var ep = host.AddServiceEndpoint(typeof (IMyService), wb, uri);
host.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
host.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new PasswordValidator();
host.Open();
Console.WriteLine("Press any key to terminate");
Console.ReadKey();
}
finally
{
if (host != null) host.Close();
}
}
}
public class PasswordValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (null == userName || null == password)
throw new ArgumentNullException();
if (userName == "Test" && password == "Password") return;
throw new WebFaultException(HttpStatusCode.Unauthorized);
}
}
I've already taken note of this other, similar question, but none of the answers posted there actually work. I'm hoping a more fully defined version of the question will elicit some better responses.
Try this:
public override void Validate(string userName, string password)
{
if (null == userName || null == password)
throw new ArgumentNullException();
if (userName == "Test" || password == "Password") return;
WebFaultException rejectEx = new WebFaultException(HttpStatusCode.Unauthorized);
rejectEx.Data.Add("HttpStatusCode", rejectEx.StatusCode);
throw rejectEx;
}
As far as I know this is an undocumented technique which relies on how the WCF stack manages exceptions internally. There ought to be a documented way but I haven't found one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With