Click here to Skip to main content
Click here to Skip to main content

Basic Authentication on a WCF REST Service

By , 28 Feb 2011
 

Contents

Introduction

This article explains a method to secure a REST based service using Basic Authentication. The service itself is implemented using Microsoft Windows Communication Foundation. The authentication of the credentials should be possible against any type of backend. For example, authenticate against an Active Directory, a custom file, or a database. Basic Authentication is a standard available in combination with WCF and IIS, but the downside of this is that authentication is only possible against an Active Directory.

Although Basic Authentication is a method to secure a web site or service, the authentication mechanism itself is not secure. The user name and password are sent Base64 encoded over the internet. To make this more secure, the server should offer the service using HTTPS. HTTPS secures the channel so that the Base64 encoded user name and password cannot be decrypted. An alternative to Basic Authentication is Digest Authentication which is also possible with WCF REST. I created a separate article on CodeProject that describes Digest Authentication on a WCF REST Service.

This article and the provided source code can be used in two ways. First, just download the code, go down to the Using the code section, and implement your WCF service using Basic Authentication. Second, you can use the article to learn what exactly is Basic Authentication and how can WCF REST be extended.

Basic Authentication

Basic Authentication is a standard protocol defined within HTTP 1.0 that defines an authentication scheme. In this scheme, the client must authenticate itself with a user-ID and password. Basic Authentication is described in RFC 2617. When a client requests a resource from a site that is protected using Basic Authentication, the server returns a 401 "Not authorized" response. Inside this response, the server has added an indication that the site is protected using Basic Authentication. The server adds WWW-Authenticate: Basic realm="site" to the header of the response; Basic indicates that the authentication scheme is Basic Authentication, and realm is a string that indicates which part of the site is protected. It has no further usage in the actual authentication mechanism itself. An internet browser generates a dialog based on this response message. This dialog shows the realm and allows a user to enter a user name and password.

When a user enters the user name and password, the client resends the request but adds "Authorization: Basic SGVsbG8gQmFzZTY0" to the header of the request. The characters after Basic are the user name and password, separated by a single colon ":" in a Base64 encoded string. The server decodes the string, extracts the credentials, and validates them against the back-end. When the credentials are correctly validated, the server returns the requested content to the client.

Extending WCF REST

To be able to integrate Basic Authentication with WCF REST, we have to extend the functionality of the WCF framework. The extension is divided into three steps:

  • Find the extension point to apply behavior to all operations of the service
  • Create a custom authentication mechanism based on existing standards
  • Create a security context based on the given credentials

Each of these steps is described in this article.

Finding the extension point, RequestInterceptor

WCF REST is part of the WCF REST Starter Kit. Unlike standard WCF, the WCF Starter Kit provides a simple way to apply the behaviour to all server operations. Adding this behavior to normal WCF can get fairly complex. WCF REST uses Request Interceptors. Request Interceptors shield you from the more complex extensibility points. Request Interceptors are executed at the WCF channel level, and enable you to interpret the incoming request and generate an appropriate response.

public class MyRequestInterceptor : RequestInterceptor
{
   public override void ProcessRequest(ref RequestContext requestContext)
   {
      //Access request with requextContext.RequestMessage
   }
}

By deriving a new class from the RequestInterceptor base class, you create a custom request interceptor. The method ProcessRequest is executed for every request that arrives at the service. Inside this method, you can read the header of the request and decode the Base64 encoded string if it is present. If it is not present, a response is generated that includes WWW-Authenticate: Basic realm="site" in the header. If it is present, we create a new security context and set the credentials on this context.

Linking the custom RequestInterceptor to the service

The RequestInterceptor can be linked to the service by creating a custom ServiceHostFactory. The ServiceHostFactory is responsible for providing instances of ServiceHost in managed hosting environments. By managed hosting environments I mean services that are hosted within IIS. The CreateServiceHost method of the ServiceHostFactory creates a new WebServiceHost and adds the new RequestInceptor to the Interceptors collection.

public class BasicAuthenticationHostFactory : ServiceHostFactory
{
   protected override ServiceHost CreateServiceHost(Type serviceType, 
                                  Uri[] baseAddresses)
   {
      var serviceHost = new WebServiceHost2(serviceType, true, baseAddresses);
      serviceHost.Interceptors.Add(RequestInterceptorFactory.Create(
                    "DataWebService", new CustomMembershipProvider()));
      return serviceHost;
   }
}

This new ServiceHostFactory is linked to the service through the markup file (.svc) of the service. Inside the markup, you add the host factory of the service.

Factory="WCFServer.BasicAuthenticationHostFactory"

Custom authentication method, creating a custom MembershipProvider

The provided source code uses a MembershipProvider to actually perform the authentication of the credentials of the client. You can write your own membership provider by deriving from MembershipProvider. The only method that needs to be implemented is the ValidateUser method. This is the method the code uses to validate the user. This custom MembershipProvider is linked to the RequestInterceptor in the CreateServiceHost method of the ServiceHostFactory.

public class CustomMembershipProvider : MembershipProvider
{
   public override bool ValidateUser(string username, string password)
   {
      //perform validation
      return false;
   }

   .....
}

Creating a security context

After we have authenticated the incoming request, we have to create and set the security context. This enables the usage of the client credentials inside a service method. WCF uses the thread local ServiceSecurityContext for this. After the request has been authenticated, a new ServiceSecurityContext is created and added to the incoming request. See the code below from the provided source code that creates a new ServiceSecurityContext.

internal ServiceSecurityContext Create(Credentials credentials)
{
   var authorizationPolicies = new List<iauthorizationpolicy>();
   authorizationPolicies.Add(authorizationPolicyFactory.Create(credentials));
   return new ServiceSecurityContext(authorizationPolicies.AsReadOnly());
}

This enables to retrieve the user name of a service method as follows:

[OperationContract]
public string DoWork()
{
   string name = ServiceSecurityContext.Current.PrimaryIdentity.Name;
   return "Hello " + name;
}

Using the code

If you want to secure your own WCF REST service with Basic Authentication using the provided source code, you need to execute the following steps:

  • Add a reference to the BasicAuthenticationUsingWCF assembly
  • Create a new Membership Provider derived from MembershipProvider
  • Implement the ValidateUser method against your back-end security storage
  • Create a custom BasicAuthenticationHostFactory, see the example in the provided source code
  • Add the new BasciAuthenticationHostFactory to the markup of the .svc file

Points of interest

Although Basic Authentication is a method to secure a web site or service, the authentication mechanism itself is not secure. The user name and password are sent Base64 encoded over the internet. To make this more secure, the server should offer the service using HTTPS. HTTPS secures the channel so that the Base64 encoded user name and password cannot be decrypted.

Basic Authentication in combination with HTTPS is used frequently when you want to offer your service to third parties and provide easy interoperable service. If however you control both side of the wire, client and server, WCF offers a standard security mechanism that can be added to your service using configuration.

This article and source code is based on the example of Pablo M. Cibraro who deserves the credits for the solution.

The provided source code is developed using TDD, and uses the NUnit framework for creating and executing tests. Rhino Mocks is used as a mocking framework inside the unit tests.

History

  • 23 Jan., 2011
    • Initial post and first version.
  • 28 Feb., 2011

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Patrick Kalkman
Architect http://www.hinttech.nl
Netherlands Netherlands
Member
Patrick Kalkman is a senior Software Architect with more than 20 years professional development experience. He works for Hinttech where he develops state of the art web applications.

Patrick enjoys writing his blog. It discusses software architectures using semantic web technologies. Patrick can be reached at pkalkie@gmail.com.
 
Published Windows 8 apps:
 
Published Windows Phone apps:
 
Awards:

Best Mobile article of March 2012
Best Mobile article of June 2012

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionError when used with https and accessing the service from the browsermemberLahsiv198113 Mar '13 - 0:28 
Hi Patrick,
Firstly, I'd like to commend you for writing such a clean piece of code, which works straight out-of-the-box.
 
I have integrated the BasicAuthenticationUsingWCF dll in my project and created the appropriate the files and that seem to work fine. But, after securing the service by using https and transport security in WCF I am unable to access the service from a browser and it returns me 'Error 103 (net::ERR_CONNECTION_ABORTED): Unknown error.'. Although, when I send request programmatically, it works fine !!!
 
Aside from above, when i run my ASP.net application containing the WCF service then locally, I get an Xmlexception 'Unexpected end of file' which I am unable to get rid off !!!
 
Any help !!!
GeneralMy vote of 2membergadasadox8 Jan '13 - 0:38 
no in depth explanation
GeneralRe: My vote of 2memberPatrick Kalkman23 Feb '13 - 21:17 
Hi gadasadox,
 
Could you explain what should be explained in depth in your opinion?
Patrick Kalkman
 
My latest article: Weekly Thai Recipe! for Windows Phone
My Blog: SemanticArchitecture.net

QuestionQuestion about Basic Authmemberjim lahey27 Sep '12 - 3:37 
Hi Patrick,
 
Thanks for the informative article, it certainly gives a good view under the hood of some of the less everyday WCF features like custom ServiceHostFactories.
 
I'm running into a problem using this though, and I wonder if you could tell me if I'm doing something wrong: if I switch my application in IIS to just use Basic, it doesn't seem to work - I can't authenticate against anything and the code for the custom service host factory never hits a breakpoint. I'm looking for a way to use custom authentication against a REST WCF service using webHttpBinding.
AnswerRe: Question about Basic AuthmemberPatrick Kalkman27 Sep '12 - 4:08 
Hi Jim,
 
You don't have to switch IIS to use Basic Authentication. Just let the WCF service do the authentication.
 
Hope this helps.
Patrick Kalkman
 
My latest article: Weekly Thai Recipe! for Windows Phone
My Blog: SemanticArchitecture.net

Question[My vote of 1] A simple client would be nicemembermsdevtech7 Aug '12 - 3:45 
That unit test project is useless, a simple client showing how this service is called would be nice.
GeneralMy vote of 5memberHai Qui23 May '12 - 1:27 
Nice article. my 5
GeneralRe: My vote of 5memberPatrick Kalkman5 Aug '12 - 21:59 
Thanks Hai Qui
Patrick Kalkman
 
My latest article: Weekly Thai Recipe! for Windows Phone
My Blog: SemanticArchitecture.net

Question.Net 4memberJP Barbosa15 Feb '12 - 14:58 
First of all: thank you so much.
Your article must be a reference.
 
So... there is any diference between this version to run in a .Net Framework 4 project?
What about Microsoft.ServiceModel.Web?
 
Regards, JP.
QuestionWill this work for SOAP Based ServicememberMuraliVS12 Jan '12 - 5:08 
If yes, what changes we need to make this work for a SOAP based Service.
QuestionHow to disable if we don't want this basic authentication? can we make this enabling/disabling configurable?memberMuraliVS9 Jan '12 - 19:12 
How to disable if we don't want this basic authentication? can we make this enabling/disabling configurable?
AnswerRe: How to disable if we don't want this basic authentication? can we make this enabling/disabling configurable?memberPatrick Kalkman10 Jan '12 - 20:35 
Sure, there are many ways to make this configurable. For example, you could hook into the ProcessRequest method and check there.
 
But if you want to disable it completely, you could remove the RequestInterceptor. It depends on your exact requirements.
Patrick Kalkman
 
My latest article: PDF reporting using ASP.NET MVC3
My Blog: SemanticArchitecture.net

QuestionPass credentials from Client applicationmembershrihan016 Nov '11 - 10:37 
Hi My client calling the WCF rest services is a windows application, I would like to pass the same credentials (used to login to windows application ) to the Rest service, I do not want a challenge credentials window to open when calling the Rest Service using RequestInterceptor and ProcessRequest
AnswerRe: Pass credentials from Client applicationmemberKarel Kral29 Dec '11 - 23:12 
Try this (from normal WCF client, but it should be the same)
ChannelFactory<TProxy> channelFactory = new ChannelFactory<TProxy>(binding, new EndpointAddress(endpointAdress));
channelFactory.Credentials.UserName.UserName = userCredentials.UserName;
channelFactory.Credentials.UserName.Password = userCredentials.Password;
Karel Kral

GeneralMy vote of 5memberAfter205018 Oct '11 - 4:32 
Nice post. I liked the style you put things up!
GeneralRe: My vote of 5memberPatrick Kalkman5 Aug '12 - 22:00 
Thanks After2050
Patrick Kalkman
 
My latest article: Weekly Thai Recipe! for Windows Phone
My Blog: SemanticArchitecture.net

QuestionHow do I make my wcf services available for particular user?memberdusshyi330 Sep '11 - 3:50 
Thank you for the great article, saved me tons of time. Can you give me some guide to set up the service for specific user? What I'm trying to do is when the user gets the prompt for his credentials once he access the service, I want to store the userName and use it through out my service! How do I do that?
 
Custom Membership Provider Code
 
Here is the code that I'm validating!
 
public override bool ValidateUser(string username, string password)
    {
        int authenticatedId = SecurityManager.Authenticate(username, password);
        if (authenticatedId != -1)
        {
            return true;
        }
 
        return false;
    }
Here is my Basic Authentication Host Factory
 
This will call my CustomMembershipProvider to replace the default web service factory.
 
public class BasicAuthenticationHostFactory : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        var serviceHost = new WebServiceHost2(serviceType, true, baseAddresses);
        serviceHost.Interceptors.Add(RequestInterceptorFactory.Create("DataWebService", new CustomMembershipProvider()));
        return serviceHost;
    }
}
Any help will be appreciated.
AnswerRe: How do I make my wcf services available for particular user?membershroin5 Jun '12 - 11:21 
I use:
 
ServiceSecurityContext.Current.PrimaryIdentity.Name
 
To validate that the proper user is accessing a particular method.
Questionstandard security mechanismmembersutikshna2 Aug '11 - 4:11 
Thanks Patrick, google shows ur article as first link deservingly Smile | :) I need small help, as you mentioned:- "If however you control both side of the wire, client and server, WCF offers a standard security mechanism that can be added to your service using configuration." Can you please tell us what are those standard security mechanism, as in my case, Only my client will be calling my own REST services.
AnswerRe: standard security mechanismmemberPatrick Kalkman14 Aug '11 - 1:01 
Hi sutikshna,
 
What I ment that if you control both sides of the wire you could use and set the most appropriate protocol. For example, you could use wsHttpBinding and use the WS-Security standards.
 
If that´s feasible in your situation I don´t know as you mention REST. Which seams that you already made a choice regarding the protocol.
 
Regards,
 
Patrick
Patrick Kalkman
 
My latest article: Androng, a Pong clone for Android
My Blog: SemanticArchitecture.net

GeneralProblem with Self-HostmemberMember 27984678 Apr '11 - 13:04 
Patrick,
 
To start with, thank you very my for posting this code. I have been struggling for a few days with setting up basic auth on my WCF RESTful API. The code you provide works great! The problem for me comes in when you attempt to use it in a self-host environment. Following are the simple steps to demonstrate the problem:
 
1. Add a Console Application to your solution with a reference to (WCFServer and BasicAuthenticationUsingWCF)
2. Replace Program.cs with the following:
using System;
using BasicAuthenticationUsingWCF;
using Microsoft.ServiceModel.Web;
using WCFServer;
 
namespace WCFServerConsole
{
class Program
{
static void Main(string[] args)
{
Uri u = new Uri("http://localhost:8000");
var serviceHost = new WebServiceHost2(typeof(Service), true, new Uri[] {u} );
serviceHost.Interceptors.Add(RequestInterceptorFactory.Create("DataWebService", new CustomMembershipProvider()));
serviceHost.Open();
Console.ReadLine();
}
}
}
 
3. Run the console application.
4. Hit http://localhost:8000/ from your browser
5. You will receive the following exception: The 'WWW-Authenticate' header cannot be modified directly.
Parameter name: name
6. If you comment out the line that adds the interceptor it works fine.
 

If you had any ideas on this I would be eternally grateful!
 

Thank you,
Brian Henry
Software Architect
Activant Solutions
GeneralRe: Problem with Self-HostmemberPatrick Kalkman9 Apr '11 - 19:20 
Hello Brian,
 
I looked into your issue. I got the same error! It seems that when you self host your rest service you are not allowed to change the www-authenticate header. There is an explicit test in the wcf source which checks if you add a protected header. I did not found a workaround.
 
What you could try is convert the source to WCF4 or host your solution in IIS. I will update this article in the future with a working WCF4 solution.
 
Patrick
GeneralRe: Problem with Self-HostmemberBrianCHenry10 Apr '11 - 7:07 
Thanks Patrick!
 
I did convert the code to WCF4 which had no affect. If I find a workaround I'll post back letting everyone know how I handled it.
 
-Brian
GeneralRe: Problem with Self-Hostmembermasti525 Oct '11 - 5:49 
Were you able to resolve this issue ? Can you please post the workaround?
 
Thanks
Mustafa
GeneralRe: Problem with Self-HostmemberSetiri16 Oct '11 - 11:40 
i need to do this as well...

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 28 Feb 2011
Article Copyright 2011 by Patrick Kalkman
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid