Alex Rivera | Logout

Adding basic HTTP auth to a WCF REST service

Asked 2011-01-17T17:01:38.307
9

I have a WCF HTTP REST Service and I tie into it with an HTTP client in a different programming language who writes its own custom HTTP. I would like to add WWW-Authenticate basic authentication support to my WCF service.

My methods look like this:

[WebInvoke(UriTemplate = "widgets", Method = "POST")]
public XElement CreateWidget(XElement e)   
{
...
}

Is it possible for me to somehow filter incoming HTTP requests so I can check for a valid Basic auth string before it hits each of the REST methods like CreateWidget above? Note: My auth info is stord in my database.

Basically I want to check for this in the request headers: Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== and then I can myself parse that string and validate the u/p in the database.

The web.config file is as follows:

<?xml version="1.0"?>
<configuration>

  <connectionStrings>
    <add name="DatabaseConnectionString" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Database;Integrated Security=True" providerName="System.Data.SqlClient" />
  </connectionStrings>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
    <httpRuntime maxRequestLength="10485760" />
  </system.web>

  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    </modules>
  </system.webServer>

  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
    <standardEndpoints>
      <webHttpEndpoint>
        <standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true" maxReceivedMessageSize="1048576" maxBufferSize="1048576" />
      </webHttpEndpoint&g
Edit
Report

3 Answers

9

I was also interested in custom authentication in a REST HTTP WCF service and finally got it to work.

That being said my code will give you a way to get it working, but I recommend reading this guide which explains everything in more depth: http://wcfsecurityguide.codeplex.com/

First, change the system.web portion of your Web.Config to look like this:

<system.web>
  <compilation debug="true" targetFramework="4.0" />
  <httpRuntime maxRequestLength="10485760" />
  <authentication mode="None"></authentication>
  <httpModules>
    <add name="BasicAuthenticationModule" type="YourNamespace.UserNameAuthenticator" />
  </httpModules>
</system.web>

Then add another file to your project: UserNameAuthenticator.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Security.Principal;
using System.ServiceModel.Activation;

namespace YourNamespace
{
    public class UserNameAuthenticator : IHttpModule
    {
        public void Dispose()
        {
        }

        public void Init(HttpApplication application)
        {
            application.AuthenticateRequest += new EventHandler(this.OnAuthenticateRequest);
            application.AuthorizeRequest += new EventHandler(this.OnAuthorizationRequest);
            application.EndRequest += new EventHandler(this.OnEndRequest);
        }

        public bool CustomAuth(string username, string password)
        {
            //TODO: Implement your custom auth logic here
            return true;
        }

        public string[] GetCustomRoles(string username)
        {
            return new string[] { "read", "write" };
        }

        public void OnAuthorizationRequest(object source, EventArgs eventArgs)
        {
            HttpApplication app = (HttpA
answered 2011-01-18T22:02:43.167
3

I've had similar problems and found a lot of different approaches, especially the cross domain calls, together with basic authentication seems to be a bit of a challenge. Jquery for example first issues an OPTIONS call to verify it the POST is allowed. Wcf normally declines this request and you get a strange error.

I've finally got it working and you can download sample code from my blog: http://sameproblemmorecode.blogspot.com/2011/10/creating-secure-restfull-wcf-service.html

answered 2011-10-30T21:02:20.723
2

Just to add to this, Chrome will not load the login dialog unless you change "BasicRealm" to "BasicRealm=site" in the OnEndRequest method:

    public void OnEndRequest(object source, EventArgs eventArgs)
    {
        if (HttpContext.Current.Response.StatusCode == 401)
        {
            //if the status is 401 the WWW-Authenticated is added to 
            //the response so client knows it needs to send credentials 
            HttpContext context = HttpContext.Current;
            context.Response.StatusCode = 401;
            context.Response.AddHeader("WWW-Authenticate", "Basic Realm=site");
        }
    }

And thanks, this is such a simple solution.

answered 2012-10-08T21:58:23.557

Your Answer