Click here to Skip to main content
15,879,184 members
Articles / Programming Languages / C#
Tip/Trick

Secure WCF RESTful service using OAUTH

Rate me:
Please Sign up or sign in to vote.
4.86/5 (23 votes)
24 Apr 2012CPOL3 min read 194.7K   67   36
How to build a security layer on top of your WCF RESTful service.

Introduction

To get started with this article, we will build a WCF RESTful service which is called the service provider and client application (in this case it's a web app) which would use services and is called the consumer. I wanted to build a security layer on top of my WCF RESTful service. So when I Googled I got many links targeting at OAUTH and all the articles and posts talking about using OAUTH with complicated examples. I could not figure out where to start.

After many clicks on Google, I found pieces of code to understand what needed to be done to provide security for my RESTful services. So in this article I will try to keep things as simple as possible and show how to achieve this complicated task.

So what is OAUTH?

OAuth is a standardization and combined wisdom of many well established industry protocols. It is similar to other protocols currently in use (Google AuthSub, AOL OpenAuth, Yahoo! BBAuth, Upcoming API, Flickr API, Amazon Web Services API, etc.).

DotNetOpenAuth is a consumer and service provider implementation for OAuth 1.0 and 1.0a for .NET, written in C#. It has built-in support for HMAC-SHA1, RSA-SHA1, and PLAINTEXT signature methods with extensibility to add others.

Many people have contributed towards OAUTH implementation for Java, .NET, PERL, PHP, etc. DevDefined OAuth has contributed for .NET. Before we start on an example, download the base class from https://oauth.googlecode.com/svn/code/csharp/OAuthBase.cs.

Now let’s get on to the code part. In this article I will not discuss how to build a RESTful service from scratch.

In my WCF RESTful service I have implemented a Get method (GetSampleMethod_Without_OAuth) without using OAUTH. Below is the simple implementation (hoping it is quite simple :))

C#
[OperationContract(Name = "GetSampleMethod_Without_OAuth")]
[WebGet(UriTemplate = "GetSampleMethod_Without_OAuth/inputStr/{name}")]
string GetSampleMethod_Without_OAuth(string name);
public string GetSampleMethod_Without_OAuth(string strUserName)
{
    StringBuilder strReturnValue = new StringBuilder();
    // return username prefixed as shown below
    strReturnValue.Append(string.Format("You have entered userName as {0}", strUserName));
    return strReturnValue.ToString();
}

To verify this method, open the browser with the URL: https://localhost/MyService.svc/GetSampleMethod_Without_OAuth/inputStr/suryaprakash.

In this case you would see the output and if you notice, this service is wide open to anyone. To overcome such issues we could go with the below implementation.

Let’s implement another method with OAuth security. This method would return the same output as above but before processing, it would check for CONSUMERSECRET which is supposed to be sent from the client to make use of the services. If the key doesn’t match it would return an unauthorized request message.

This consumer secret can be shared with multiple clients. Apart from the consumer secret there are parameters like oauth_timestamp, oauth_nonce, URL, etc., which are to be sent (more details on https://oauth.net/code/).

In my case the consumer secret is “suryabhai” which has to be sent along with the service call. The authenticate method would read all input parameters and send it to the OAuthBase class, and finally it would return true or false which will define whether to process the request or deny it.

Let's look at the below code:

C#
[OperationContract(Name = "GetSampleMethod_With_OAuth")]
[WebGet(UriTemplate = "GetSampleMethod_With_OAuth/inputStr/{name}")]
string GetSampleMethod_With_OAuth(string name);
public string GetSampleMethod_With_OAuth(string strUserName)
{
    if (Authenticate(WebOperationContext.Current.IncomingRequest))
    {
        StringBuilder strReturnValue = new StringBuilder();
        // return username prefixed as shown below
        strReturnValue.Append(string.Format("You have entered userName as {0}", strUserName));
        return strReturnValue.ToString();
    }
    else
    {
        WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Unauthorized;
        return "Unauthorized Request.";
    }
}

private static bool Authenticate(IncomingWebRequestContext context)
{
    bool Authenticated = false;
    string normalizedUrl;
    string normalizedRequestParameters;
    //context.Headers
    NameValueCollection pa = context.UriTemplateMatch.QueryParameters;
    if (pa != null && pa["oauth_consumer_key"] != null)
    {
        // to get uri without oauth parameters
        string uri = context.UriTemplateMatch.RequestUri.OriginalString.Replace
            (context.UriTemplateMatch.RequestUri.Query, "");
        string consumersecret = "suryabhai";
        OAuthBase oauth = new OAuthBase();
        string hash = oauth.GenerateSignature(
            new Uri(uri),
            pa["oauth_consumer_key"],
            consumersecret,
            null, // totken
            null, //token secret
            "GET",
            pa["oauth_timestamp"],
            pa["oauth_nonce"],
            out normalizedUrl,
            out normalizedRequestParameters
            );
        Authenticated = pa["oauth_signature"] == hash;
    }
    return Authenticated;
}

So far so good, the implementation is done, now let's open the browser and call the service: https://localhost/MyService.svc/GetSampleMethod_With_OAuth/inputStr/suryaprakash.

When you make a request to the GetSampleMethod_With_OAuth method as above, the service would return “UNAUTHORIZED REQUEST” as we did not supply the consumer secret and other parameters. To complete this article, let’s go ahead and implement a client which will call the above method by sending all the necessary inputs/parameters.

As part of the client implementation, we would make a call to the service using a WebRequest by providing all the necessary parameters and the client code has to use the same consumer secret shared by the service.

In the default.aspx.cs PageLoad event, add the below code. The client also has to include the OAuthBase class from https://oauth.googlecode.com/svn/code/csharp/OAuthBase.cs.

C#
string consumerKey = "test";
string consumerSecret = "suryabhai";
var uri = new Uri("http://localhost/MyService.svc/GetSampleMethod_With_OAuth/inputStr/suryaprakash");
string url, param;
var oAuth = new OAuthBase();
var nonce = oAuth.GenerateNonce();
var timeStamp = oAuth.GenerateTimeStamp();
var signature = oAuth.GenerateSignature(uri, consumerKey,
consumerSecret, string.Empty, string.Empty, "GET", timeStamp, nonce,
OAuthBase.SignatureTypes.HMACSHA1, out url, out param);
WebResponse webrespon = (WebResponse)WebRequest.Create(
   string.Format("{0}?{1}&oauth_signature={2}", url, param, signature)).GetResponse();
StreamReader stream =new StreamReader(webrespon.GetResponseStream());
txtResult.Text = stream.ReadToEnd();

Now let’s call the service by opening the default.aspx page in browser. As we are using a valid consumer secret, the output would be as expected. Now let’s modify the consumer secret and open default.aspx. In this case the expected output is “UNAUTIRUZED REQUEST”.

My example talks about only the GET method and sending data in a query string but it can be extended for a POST method as well and we can send data in headers instead of the query string.

Happy coding… Hope this helps!

License

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



Comments and Discussions

 
QuestionOAuthBase class does not exists Pin
Member 1352417515-Nov-17 20:47
Member 1352417515-Nov-17 20:47 
QuestionSource Code Pin
Madhu Nair25-May-16 19:28
Madhu Nair25-May-16 19:28 
AnswerRe: Source Code Pin
vivekkumar114328-Jun-16 23:12
vivekkumar114328-Jun-16 23:12 
QuestionAuthentication is not consistent Pin
venkatpv30-Mar-16 3:47
venkatpv30-Mar-16 3:47 
AnswerRe: Authentication is not consistent Pin
vivekkumar1143222-May-16 22:48
vivekkumar1143222-May-16 22:48 
QuestionWCF Security Pin
Member 1194245126-Nov-15 20:33
Member 1194245126-Nov-15 20:33 
QuestionSecure WCF RESTful service using OAUTH with token & token secret Pin
silambuselvan4-Nov-15 0:47
silambuselvan4-Nov-15 0:47 
GeneralException when run Pin
Member 1194245113-Oct-15 19:47
Member 1194245113-Oct-15 19:47 
GeneralRe: Exception when run Pin
Member 1194245113-Oct-15 20:13
Member 1194245113-Oct-15 20:13 
QuestionWhat if my consumer is iPhone ? How to configure key / secrete word in iPhone Pin
patel_javal12-Oct-15 2:22
patel_javal12-Oct-15 2:22 
AnswerRe: What if my consumer is iPhone ? How to configure key / secrete word in iPhone Pin
Member 1194245126-Nov-15 20:38
Member 1194245126-Nov-15 20:38 
QuestionFails to authenticate when host the service in iis Pin
chanukajr12-Aug-15 21:31
chanukajr12-Aug-15 21:31 
QuestionI found The remote server returned an error: (400) Bad Request. Pin
Member 110822247-Apr-15 20:58
Member 110822247-Apr-15 20:58 
Question401 allways Pin
Member 849768315-Sep-14 10:49
Member 849768315-Sep-14 10:49 
AnswerRe: 401 allways Pin
Member 1030887620-Jan-17 2:32
Member 1030887620-Jan-17 2:32 
QuestionQuery for Post Request Pin
Susheel Kumar Verma28-Aug-14 3:11
Susheel Kumar Verma28-Aug-14 3:11 
QuestionWhere to get CONSUMERSECRET to provide various clients, will be consuming my webservice? Pin
NAPorwal(8015059)4-Jun-14 8:23
NAPorwal(8015059)4-Jun-14 8:23 
QuestionWhere is actual authentication Pin
londondev2120-May-14 3:28
londondev2120-May-14 3:28 
QuestionThe remote server returned an error: (401) Unauthorized Pin
Vjoyism24-Apr-14 21:30
Vjoyism24-Apr-14 21:30 
SuggestionSolving repeated requests failure Pin
Jung Hyun, Nam2-Mar-14 20:11
professionalJung Hyun, Nam2-Mar-14 20:11 
QuestionIncomingWebRequestContext.UriTemplateMatch Pin
Member 103788486-Nov-13 3:19
Member 103788486-Nov-13 3:19 
QuestionSend POST Request Pin
Member 103788484-Nov-13 2:49
Member 103788484-Nov-13 2:49 
Questionsecurity of oauth parameters on cosumer side Pin
bhupinder719-Mar-13 7:32
bhupinder719-Mar-13 7:32 
QuestionSend POST request Pin
pankaj.thadani24-Feb-13 20:51
pankaj.thadani24-Feb-13 20:51 
QuestionUnAuthorized User Pin
zubreha8-Jan-13 8:24
zubreha8-Jan-13 8:24 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.