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

Digest Authentication on a WCF REST Service

By , 27 Feb 2011
 

Contents

Introduction

This is a follow-up on my earlier article that described how to use BASIC Authentication with a WCF REST Service. The disadvantage of that solution was that you need a https tunnel to really secure the username password verification process. Although possible, this is not always a feasible situation, for example, if you don't want to invest in certificates or loose performance when using a https tunnel.

This article explains a different authentication mechanism called Digest Authentication which provides an alternative. This security mechanism is more secure than Basic Authentication and does not have the drawbacks from using a https tunnel.

Digest Authentication is available on multiple web servers and supported by multiple internet browsers. The drawback when using Digest Authentication with Internet Information server is that it automatically authenticates credentials against active directory. This article describes an implementation which enables you to secure a WCF REST service with Digest Authentication and authenticate against any back-end.

Digest Authentication was first described in RFC 2069 as an extension to HTTP Basic Authentication. Later, the verification algorithm and security was improved by RFC 2617. This is the current stable specification. The implementation in this article is based on that RFC 2617 specification. Digest Authentication is more secure because it uses MD5 cryptographic hashing and the use of a nonce to discourage cryptanalysis.

Overview of Digest Communication

Digest communication starts with a client that requests a resource from a web server. If the resource is secured with Digest Authentication, the server will respond with the http status code 401, which means Unauthorized.

Digest Authentication Communication

In the same response, the server indicates in the HTTP header with which mechanism the resource is secured. The HTTP header contains the following "WWW-Authenticate: Digest realm="realm", nonce="IVjZjc3Yg==", qop="auth". The first thing you should notice is the string Digest in the response, here the server indicates that the resource that was requested by the client is secured using Digest Authentication. Secondly, the server indicates the type of Digest Authentication algorithm to use by the client with Quality Of Protection (QOP) and the string called nonce which I will explain later in this article.

An internet browser responds to this by presenting the user a dialog, in this dialog the user is able to enter his username and password. Note, that this dialog does not show the warning about transmitting the credentials in clear text as with a Basic Authentication secured site.

Digest Authentication Credentials Screen

When the user enters the credentials in this dialog, the browser requests the resource from the server again. This time, the client adds additional information to the HTTP header regarding Digest Authentication.

Digest Authentication Second

The server validates the information and returns the requested resource to the client. The details of the response from the server and the additional request of the client will be described in the following part of this article.

Digest Authentication

When the server responds to an unauthenticated client request, the server adds a nonce and a qop key to the header of the HTTP response. Both are typical for Digest Authentication. First, the nonce will be described and second the QOP quality of protection.

The Nonce

The Nonce stands for "Number used Once", this is a pseudo random number that ensures that old communications between a client and a server cannot be reused in replay attacks. A replay attack is a network attack in which previous valid data transmission is repeated. This is done by an adversary who intercepts the data and retransmit it. According to the RFC 2716 specification, the Nonce is a server specified data string which should be uniquely generated each time a 401 response is returned by the server. The 401 response that is sent back to the client includes the Nonce generated by the server. According to RFC 2716, the client should add this nonce to the header of next requests.

Generating the Nonce

The format of the nonce depends on the implementation. Each RFC 2617 digest authentication implementation may define their own nonce format. However, one should carefully design the format of the nonce as it is a part of the quality of the security. For my implementation, I choose to include a date time stamp and the IP address of the client into the nonce. The implementation generates the nonce as follows.

Nonce = Base64( TimeStamp : PrivateHash)

The nonce is generated by base64 encoding the string that is constructed by concatenating the time stamp, a colon and a generated private hash. In the source code, this is handled by the NonceGenerator class which has a Generate method that generates the Nonce string.

public string Generate(string ipAddress)
{
   double dateTimeInMilliSeconds =
      (DateTime.UtcNow - DateTime.MinValue).TotalMilliseconds;
   string dateTimeInMilliSecondsString =
      dateTimeInMilliSeconds.ToString();
   string privateHash = privateHashEncoder.Encode(
      dateTimeInMilliSecondsString,
      ipAddress);
   string stringToBase64Encode =
      string.Format("{0}:{1}", dateTimeInMilliSecondsString, privateHash);
   return base64Converter.Encode(stringToBase64Encode);
}

MD5 is used to generate the private hash of the string that is constructed by concatenating the time stamp, a colon, the IP address of the client, a colon and a private key that is only known to the server. As MD5 is used, the generation is one-way. It is not possible to reconstruct this information from the private hash.

PrivateHash = MD5Hash( TimeStamp : IP Address : Private key)

In the source code, generating the private hash is handled by the method Encode in the PrivateHashEncoder class. It uses the MD5Encoder class to actually generate the MD5 hash.

public string Encode(string dateTimeInMilliSecondsString,
    string ipAddress)
{
  string stringToEncode = string.Format(
     "{0}:{1}:{2}",
     dateTimeInMilliSecondsString,
     ipAddress,
     privateKey);
  return md5Encoder.Encode(stringToEncode);
}

Validating the Nonce

Every time the client sends the nonce to the server, the server validates if this is the nonce that the server sends to the client. The server validates the nonce in two steps:

The first thing that this implementation on the server does is validate if this PrivateHash was generated by this server and returned to this client. The server does this by generating the PrivateHash with the time stamp that is available in the Nonce and the IP address of the client. If this does not deliver the same PrivateHash as in the nonce from the client, the nonce is incorrect and the server responds with a 401. The NonceValidator is responsible in the source code for validating this nonce.

public virtual bool Validate(string nonce,
   string ipAddress)
{
   string[] decodedParts = GetDecodedParts(nonce);
   string md5EncodedString = privateHashEncoder.Encode(
      decodedParts[0],
      ipAddress);
   return string.CompareOrdinal(
      decodedParts[1],
      md5EncodedString) == 0;
}

Secondly, the server checks if the Time Stamp is too old. The server holds a certain time-out for a nonce. For example, the time-out is 300 seconds. The server validates if the time stamp in the nonce is not older than 300 seconds. If the nonce is older than 300 seconds, the server returns an indication in the HTTP header that the received nonce is too old together with a new nonce. RFC 2617 uses a special key called Stale in the header that is sets to true when the Nonce is too old. The NonceValidator is also responsible for checking if the time stamp is too old.

public virtual bool IsStale(string nonce)
{
   string[] decodedParts = GetDecodedParts(nonce);
   DateTime dateTimeFromNonce =
      nonceTimeStampParser.Parse(decodedParts[0]);
   return dateTimeFromNonce.AddSeconds(
      staleTimeOutInSeconds) < DateTime.UtcNow;
}

By using a time stamp and the IP address in the nonce, we make sure that the request is recent and comes from the client that requested the resource.

Quality Of Protection

Digest Authentication allows the server to ask which algorithm the client should use to encrypt the credentials of the user. Digest Authentication allows the following Quality Of Protection.

  • none = Default protection compatible with RFC 2069
  • auth = Increased protection that includes a client nonce and a client nonce counter
  • auth-int = Increased protection and integrity that included all of auth and a hash of the contents of the body

Note that it is a request from the server, the client itself is allowed to choose a lesser secure qop algorithm. If the server requests for auth, it is ok for the client to start communicating with the default or none qop.

The implementation with this article supports both default/none and auth. The class DefaultDigestEncoder and the class AuthDigestEncoder implement the default and the auth type of quality of protection. Both classes derive from DigestEncodeBase which holds common functionality.

DigestEncoder

At runtime, the server instantiates both types of encoders and stores them in a dictionary with the qop algorithm as the key. This enables the server to easily switch between different types of encoders at runtime.

internal class DigestEncoders :
   Dictionary
{
 public DigestEncoders(MD5Encoder md5Encoder)
 {
  Add(DigestQop.None, new DefaultDigestEncoder(md5Encoder));
  Add(DigestQop.Auth, new AuthDigestEncoder(md5Encoder));
 }

 public virtual DigestEncoderBase GetEncoder(DigestQop digestQop)
 {
  return this[digestQop];
 }
}

None or Default QOP

When an internet browser receives 401 HTTP status code with Digest in the authentication header, it will show a dialog for entering the username and password. When the client uses the default qop which is compatible with RFC 2069, the client encrypts the user name and password as follows.

HA1 = MD5( username : realm : password)

HA2 = MD5( method : digestURI)

response = MD5( HA1 : nonce : HA2)

An MD5 hash is created from the user name, realm and password, a separate MD5 hash is created from the HTTP method and the URI of the resource that the client requests. The response is created through a MD5 hash that combines the previous two MD5 hashes and the server generated nonce. The DigestEncoderBase class holds the functionality to generate both the HA1 and HA2 hashes.

private string CreateHa1(DigestHeader digestHeader,
   string password)
{
  return md5Encoder.Encode(
    string.Format(
    "{0}:{1}:{2}",
    digestHeader.UserName,
    digestHeader.Realm,
    password));
}

private string CreateHa2(DigestHeader digestHeader)
{
  return md5Encoder.Encode(
    string.Format(
    "{0}:{1}",
    digestHeader.Method,
    digestHeader.Uri));
}

The base classes AuthDigestEncoder and DefaultDigestEncoder are responsible for generating the response. This last step, generating the response, is what differs in the two derived classes. The response of the Auth algorithm should be generated differently. The Auth algorithm includes a nonceCount and a client generated Nonce in the response. Also, the actual qop string is concatenated before the hash is calculated.

response = MD5( HA1 : nonce : nonceCount : clientNonce : qop : HA2)

This is why the Auth algorithm is more secure than Default, the server performs an additional check to see if the nonceCount is incremented by the client with every request. The CreateResponse method of the AuthDigestEncoder generates the Auth response.

public override string CreateResponse(
   DigestHeader digestHeader,
   string ha1,
   string ha2)
{
  return
   md5Encoder.Encode(
     string.Format(
     "{0}:{1}:{2}:{3}:{4}:{5}",
     ha1,
     digestHeader.Nonce,
     digestHeader.NounceCounter,
     digestHeader.Cnonce,
     digestHeader.Qop.ToString(),
     ha2));
}

Extending WCF REST

To be able to integrate Digest Authentication with WCF REST, the WCF REST framework has to be extended. This is done by creating a custom RequestInterceptor. For more information, take a look at my previous article on CodeProject which explains this extension in more detail.

Retrieving and Storing User Credentials

The password of the user is transmitted as part of the response generated by the client to the server. It is not possible for the server to extract the password from the response. The server generates a response and checks if the response is equal to the response that was given by the client. This means that there are two options for storing and retrieval of user credentials using Digest Authentication.

  • The first and most secure option is for every user to store the HA1 key in the credentials data storage and validate using the stored HA1 key. This has a disadvantage because you have to change the HA1 key in the data storage if the username, password or realm changes.
  • The second option is to store the password of the use in the credentials data storage in such a way that it is possible to retrieve the original password. This is obviously less secure than the first option.

Using the Source 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 DigestAuthenticationUsingWCF assembly
  • Create a custom membership provider derived from MembershipProvider
  • Implement the ValidateUser method against your back-end security storage
  • Create a custom membership user derived from Membership user
  • Implement the GetUser method against your back-end security storage
  • Create a custom DigestAuthenticationHostFactory, see the example in the provided source code
  • Add the new DigestAuthenticationHostFactory to the markup of the .svc file

Points of Interest

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

  • 28th Feb, 2011
    • Initial post

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
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
Follow on   Twitter

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   
QuestionQuestion Regarding Adding WCF Service on Client Side.memberMember 850020721-Sep-12 3:26 
Hello Patrick,
 
Thanks for posting such a nice article. i was just looking for the same.
 
i have only a question is which id and password i should used while adding service reference on clientside.
i have tried couple of username and password pairs like "username- Willem, Password- "N" // "username- Willem, Password- "Wever"". but its not allowing me to add a service reference.
 
Also while viewing the service.svc in bowser it gives me error like "Resource not available".
 
Thanks in Advance.
Questionmissing svc file and not able to implement ServiceHostFactorymemberManu Gino26-Jul-12 15:23 
Hello,

How can I use digest authentication if I haven't the SVC file because I'm using .net 4.0 and instead I have global.asax file.
Another problem is that I'm using ninject that has its own implementation of the ServiceHostFactory.

Thanks
Questioncan you help memembernew soft7-Apr-12 1:23 
I want to modify your project to use hmac instead of md5.Confused | :confused:
AnswerRe: can you help mememberPatrick Kalkman9-Apr-12 20:50 
Hello new soft,
 
There is a class in the solution called MD5Encoder which is responsible for encoding the string. You could replace this class by a different encoder class. This new class could then use one of the classes from the .Net Framework for calculating HMac hashes such as HMACMD5.
 
Hopes this helps.
Patrick Kalkman
 
My latest article: Blue Hour, a Windows Phone application
My Blog: SemanticArchitecture.net

GeneralExcellent ReadmemberKeithBarrett23-Feb-12 9:14 
Thank you for putting this article together. It was a most enjoyable read.
GeneralRe: Excellent ReadmemberPatrick Kalkman23-Feb-12 22:03 
Thanks Keith!
Patrick Kalkman
 
My latest article: PDF reporting using ASP.NET MVC3
My Blog: SemanticArchitecture.net

QuestionGreat article to implement the authentication on WCF REST. Small help requiredmemberBharadwajSonti24-Jan-12 2:46 
I am implementing a set of WCF REST Services and exposing them from a domain on port : 4567
 
For Authentication purposes, i am using the digest authentication, and authenticating a request to a resource using DigestAuthenticationInterceptor and my CustomMembershipProvider.
 
I have a client in html and javascript from another domain accessing this protected REST service. hence i modified the ProcessRequest to also include Access-Control-Allow-Origin to the Header before replying.
But in my javascript ajax call, neither do i get WWW-Authenticate header nor Access-Control-Allow-Origin header. All i see is the following in javascript Ajax call:
 
Content-Type: application/xml; charset=utf-8
Cache-Control: private
 
Can you please help me in figuring out where would the request header might have been modified to this.
 
By the way javascript gets the "401" "UnAuthorized" status code correctly. Any help would be really really a saviour for me !!!!!
AnswerRe: Great article to implement the authentication on WCF REST. Small help requiredmemberPatrick Kalkman23-Feb-12 22:02 
Hi BharadwajSonti,
 
Are you still working on this and have the described issues? Saw you question too late.
Patrick Kalkman
 
My latest article: PDF reporting using ASP.NET MVC3
My Blog: SemanticArchitecture.net

QuestionHosted solution adding extra headersmemberdbullen21-Sep-11 10:04 
I wondered if anyone had tried deplying this to the www?   When I try it, the first unauthenticated request is answered with a 401 and the correct WWW-Authenticate: Digest header, but also with additional WWW-Authenticate: Negotiate and WWW-Authenticate: NTLM headers.   Obviously browsers go with the best security option, so it's trying to use negotiate.
Anyone else had this?
QuestionDo not use the word "Digest" in your URImemberdbullen20-Sep-11 8:04 
Further to the problem I was experiencing - see my other reply - I eventually found out that you cannot have the word "Digest" anywhere in your URI, as this will get stripped out (by RemoveDigestFromHeaderString in the DigestHeaderParser class, which is called by DigestHeaderParser.Parse), resulting in a wrongly calculated expected response.   I had called my test project folder /WhatsOn-v2-Digest/, but DigestHeaderParser strips that to /WhatsOn-v2-/, leading to it wrongly calculating the expected response.
Hope this helps someone.
Thanks again to Patrick for his great code, made a complex subject very simple.
AnswerRe: Do not use the word "Digest" in your URImemberPatrick Kalkman20-Sep-11 8:30 
Thank you Dean for providing the feedback and sharing the solution!
Patrick Kalkman
 
My latest article: Androng, a Pong clone for Android
My Blog: SemanticArchitecture.net

QuestionGreat article but having trouble implementingmemberdbullen18-Sep-11 9:27 
Hi Patrick. Thanks so much for posting this.   I've tried really hard to get this to work but the response I get from the browser when I correctly enter a password just doesn't match the response the code is expecting.   I verified that the code is expecting the correct value according to your MD5( HA1 : nonce : HA2) rule, but the browser returns a different value and obviously I can't decrypt that to see where the problem is.   Do you know of any tools that will allow me to see what's going on in the browser (e.g. the individual values it uses to generate its response)? Or can you think of any other way I can establish why the browser is sending the value it is?   This is all on my local machine with ASP.NET's default web server - will that make a difference (e.g. to the digest URI it uses in its response?) Best wishes, Dean
AnswerRe: Great article but having trouble implementingmemberPatrick Kalkman18-Sep-11 21:45 
Hi Dean,
 
When the browser sends its initial request the server returns information that the client uses to encrypt the username and password. For example the server returns the type of qop that it supports and the expected nonce.
 
All browsers use somewhat different implementation of this specification. Most support RFC 2069 and some support a part of RFC 2617. For me the best way to handle such a a problem is to create a simple unit test that checks the expected and the result value. This may enable you to pinpoint the exact step that is going wrong. Is is the validation of the nonce or something else?
 
Patrick
Patrick Kalkman
 
My latest article: Androng, a Pong clone for Android
My Blog: SemanticArchitecture.net

GeneralRe: Great article but having trouble implementingmemberdbullen19-Sep-11 2:18 
Hi Patrick.   Thanks so much for the reply.   I’ve put Debug.Write statements throughout the code, and hardcoded the nonce temporarily by setting dateTimeInMilliSecondsString to 00000000000001 so that the value I expect back remains constant.   I’ve implemented a simple XML membership provider.   Following the debug messages, I can see how the nonce is calculated by the server – it all matches up to what your article describes.   When I make my request from the browser I get back exactly what I would expect (I’ve set the qop to none/default for the time being).   When I put my credentials into the browser I get back the correct nonce, username, etc, and the response.   Back on the server my user gets retrieved and then I take their password, the nonce, method, URI etc and work out what the browser response should be.   I’ve been through every stage of that process, it all looks great.   But the browser response <> the server calculated value so a 401 is returned.   As I say, it makes perfect sense to me why the server is expecting the response it is, because it matches your formula perfectly.   But the browser’s response is different.   Obviously what I really wish I could do is see the individual pieces the browser is using to generate its response (e.g. is it using an absolute URI instead of a relative one?).   Does anyone have any ideas?   Been at this for days and really stumped!   Tried on IE9, FF 6.0.2 and Chrome 14.
GeneralRe: Great article but having trouble implementingmemberdbullen20-Sep-11 0:34 
I can actually put some more detail on this and tell you the exact values I am expecting and receiving.  
Whilst I’m debugging I have hardcoded the timestamp in NonceGenerator to 00000000000001.   As I’m running it locally my IP address is 127.0.0.1.   I’ve left the private key as MyPrivateKey, so my private hash should be MD5(00000000000001:127.0.0.1:MyPrivateKey), which is a12b90f1ef24e6e470c0c690a5b18532.   My Nonce is therefore Base64(00000000000001:a12b90f1ef24e6e470c0c690a5b18532) = MDAwMDAwMDAwMDAwMDE6YTEyYjkwZjFlZjI0ZTZlNDcwYzBjNjkwYTViMTg1MzI=.   I have also set the QOP to none/default for ease of debugging.
 
When I make my first, unauthenticated request from a browser, I can see this nonce being correctly returned (using Fiddler):
 
<pre>WWW-Authenticate: Digest realm="DataWebService", nonce="MDAwMDAwMDAwMDAwMDE6YTEyYjkwZjFlZjI0ZTZlNDcwYzBjNjkwYTViMTg1MzI="</pre>
 
Upon correctly entering my credentials (username: dbullen, password: password1) into the browser, the request is re-sent with the following header.
 
<pre>Authorization: Digest username="dbullen",realm="DataWebService",nonce="MDAwMDAwMDAwMDAwMDE6YTEyYjkwZjFlZjI0ZTZlNDcwYzBjNjkwYTViMTg1MzI=",uri="/WhatsOn-v2-Digest/WhatsOn/Service.svc/DoWork",response="6ab076a60a068465ad1b5eb29ea9fc6a"</pre>
 
Back on the server my custom membership provider correctly retrieves the user dbullen and the password password1, and then the DefaultDigestEncoder’s CreateResponse method creates the response it is expecting from the browser.   It creates the HA1 string as MD5(dbullen:DataWebService:password1) = 84de78b7b1dfe494720ca432d6ea3ec8 and the HA2 as MD5(GET:/WhatsOn-v2-/WhatsOn/Service.svc/DoWork) = c8f8b42c54b6f9a5df5f77eefdef4386.   The expected response is therefore MD5(84de78b7b1dfe494720ca432d6ea3ec8: MDAwMDAwMDAwMDAwMDE6YTEyYjkwZjFlZjI0ZTZlNDcwYzBjNjkwYTViMTg1MzI=:c8f8b42c54b6f9a5df5f77eefdef4386), which is c132dc891fdc5fd28ff4fdef741390d9 - not a match with the response the browser returned.
 
At every stage your code is doing what I would expect, but the browser’s response just does not match.
GeneralRe: Great article but having trouble implementingmemberdbullen20-Sep-11 7:55 
I've got it!   Finally!   Will post the fix as a separate reply as I think it may help others.
GeneralRe: Great article but having trouble implementingmemberani_198029-Nov-11 5:32 
Can you please point me to the fix?
GeneralRe: Great article but having trouble implementingmemberMember 996201124-Apr-13 20:58 
Please share that fix since I am also facing the same issue.
While running the URL http://localhost:59175/Service.svc
 
It redirects to
http://localhost:59175/login.aspx?ReturnUrl=%2fService.svc
GeneralRe: Great article but having trouble implementingmemberBharadwajSonti27-Jan-12 4:26 
Hi,
 
I am facing the same issue when i am sending the Authorization header with response calculated from javascript. Could you please help me with what you have done to fix the issue of mismatch between the browser response and response calculated by digestvalidator.
 
Please help me !!!!
QuestionImplementing this model along with Form authenticationmemberMember 819129826-Aug-11 8:09 
I have a site with several pages secured with form authentication through a default login screen. I have added to this site a WCF Rest service that I allowed public access to (no redirect to login page) so that I could implement your Digest Authentication on it.
 
After running your test service fine, I moved on to putting it into my site. However, now when I try to hit my service, it sends me to my login page. Even after logging into it, it continues to redirect to itself.
 
Any idea what might be going on?
AnswerRe: Implementing this model along with Form authenticationmemberPatrick Kalkman18-Sep-11 21:48 
Hi,
 
Without some more information I cannot see what is going on.
 
Sorry,
 
Patrick
Patrick Kalkman
 
My latest article: Androng, a Pong clone for Android
My Blog: SemanticArchitecture.net

QuestionDigest Auth for Non-REST WCF self-hosted ServicesmemberBeppi29-Jul-11 0:41 
Hi Patrick,
 
do you have any idea how do enable Digest Auth for WCF web services (not REST!)?
I would like to get Digest running without the need of a domain controller.
 
I am currently struggling with modifying the WWW-Authenticate HTTP header. It seems to me it is not possible to modify them.
 
I took your code and the sample code from this post http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/55ef7692-25dc-4ece-9dde-9981c417c94a/ in order to have a behavior that I can add the service endpoint and the operations. The basic idea is to intercept the request and either forward it to the operation invoker or to bypass everything and return your authetication message directly.
 
Do you have any suggestion?
Thanks, Axel
AnswerRe: Digest Auth for Non-REST WCF self-hosted ServicesmemberPatrick Kalkman14-Aug-11 0:56 
Hi Axel,
 
I have looked into it in the past. But under some circumstances it is not possible to modify the WWW-Authenticate HTTP header. It is explicitly checked in the WCF source code.
 
The sample code from your link looks feasible, it is basically the same as the REST variant.
 
Success and let me know how if you did get it to work.
 
Regards,
 
Patrick
Patrick Kalkman
 
My latest article: Androng, a Pong clone for Android
My Blog: SemanticArchitecture.net

GeneralHow can the consumer make consecutive requests to the provider which integrated the Digest Auth security layer ?memberuyhung23-May-11 23:37 
Hi Patrick
I intend to build an API for our system, which are WCF RESTful web services will be called from mobile, third-party websites. Thanks so much your source code, I've successfully built and integrated the both Basic Auth and Digest Auth into our system. But I see that the provider just generate and return the nonce only in 401 Response, not in successful responses. So if the consumer want to make consecutive requests to the provider, the process have to be:
1.The consumer make a "dummy" request to the provider that without the Authorization header
2.Provider return a 401 response with the WWW-Authenticate header that contain the Nonce value
3.The consumer parse the response, extract the Nonce value, and make a real request that the header include the Authorization
4.The provider return requested resource. But in this response, I see that the provider doesn't generate and include the new Nonce value (there's not the WWW-Authenticate or something like that), so if the consumer want to make a new request it has to:
5.The consumer have to make the "dummy" request to the provider (without Authorization header)
6.Provider return a 401 response with the WWW-Authenticate header that contain a new Nonce value
etc...
Is there something wrong here ? Or I don't understand exactly the process ?
Thanks in advanced
Hung.Nguyen

GeneralRe: How can the consumer make consecutive requests to the provider which integrated the Digest Auth security layer ?memberPatrick Kalkman25-May-11 20:03 
Hi Hung Nguyen,
 
Thank you for your feedback.
 
What you describe is a possible scenario.
 
But it is also possible to perform multiple requests using the same nonce, the nonce includes a server generated datetime stamp. If this time stamp is tool old (stale) the server will not be able to authorize your request and will send a new nonce. See the method nonceValidator.IsStale(digestHeader.Nonce) in the source code for the check.
 
The official RFC for Digest says that the implementation should return a stale=TRUE in the return header. You then could distinguis between an unauthorized request and a stale request. I have not implemented this bevhaviour. Maybe you could Wink | ;-)
 
Currently the timeout for the stale check is set to 600second, you could increase it to allow more requests before having to use a new nonce. But this is a balance between performance and security.
 
Let me know how it goes.
 
Regards,
Patrick Kalkman
 
My latest article: Androng, a Pong clone for Android
My Blog: SemanticArchitecture.net

AnswerRe: How can the consumer make consecutive requests to the provider which integrated the Digest Auth security layer ?memberuyhung25-May-11 22:57 
Thank you so much for answering my questions.
So, if the consumer want to make consecutive requests, it can use the same nonce until that nonce is stale. I just don't understand why the provider doesn't generate and return a new nonce for every responses (even a succesful response).
And do you have an similar article for OAuth protocol ? I wonder if OAuth is a replacement of the both Basic Auth and Digest ?
Thanks again and have a good time Patrick Smile | :) Smile | :)
softmaster

GeneralRe: How can the consumer make consecutive requests to the provider which integrated the Digest Auth security layer ?memberPatrick Kalkman26-May-11 22:11 
uyhung wrote:
So, if the consumer want to make consecutive requests, it can use the same nonce until that nonce is stale. I just don't understand why the provider doesn't generate and return a new nonce for every responses (even a succesful response).

That is just how it is described in the RFC 2617 standard, you could try to change it Wink | ;-)
uyhung wrote:
And do you have an similar article for OAuth protocol ? I wonder if OAuth is a replacement of the both Basic Auth and Digest ?

I don't have written an article abour OAuth, it is a totally different subject. Try a search here on CodeProject because someone might have written an article.
 
Success with your project.
Patrick Kalkman
 
My latest article: Androng, a Pong clone for Android
My Blog: SemanticArchitecture.net

GeneralDynamically configure which service methods require secure authenticate or notmemberuyhung9-Apr-12 0:22 
Hi Patrick
My service has some methods require secured authentication but some others not. Could you please help me how can I do it ?
Thanks and have a good time Patrick
softmaster

GeneralRe: Dynamically configure which service methods require secure authenticate or notmemberPatrick Kalkman9-Apr-12 20:53 
Hi uyhung,
 
I think the easiest thing to do is to create two different services, one secure and one not secure.
Patrick Kalkman
 
My latest article: Blue Hour, a Windows Phone application
My Blog: SemanticArchitecture.net

GeneralMy Vote of 5memberRaviRanjankr1-Mar-11 21:45 
thanks for share it
GeneralRe: My Vote of 5memberPatrick Kalkman2-Mar-11 11:16 
Thank you RaviRanjankr
GeneralGreat article, againmemberKai Friis1-Mar-11 21:07 
Love this artcile as well.
GeneralRe: Great article, againmemberPatrick Kalkman2-Mar-11 11:16 
Thank you Kai.
GeneralServiceAuthorizationManager worked here too.memberKai Friis3-Mar-11 7:45 
No surprise, using the same method to adjust your basic authentication code to use ServiceAuthorizationManager also worked with your Digest Authentication code. Again thank you for great articles. They helped me a ton.
GeneralRe: ServiceAuthorizationManager worked here too.memberPatrick Kalkman3-Mar-11 9:25 
Hi Kai,
 
Thanks for your feedback and suggestion. I will add a new version of the source code to the articles. This source code will include both the WCF Rest version and the "normal" WCF solution.
 
Patrick
GeneralRe: ServiceAuthorizationManager worked here too.memberKai Friis3-Mar-11 21:00 
Just to clearify. I used the WCF 4 Rest version.
GeneralMy vote of 5memberalhambra-eidos1-Mar-11 2:47 
More articles about security and WCF will be useful.
GeneralRe: My vote of 5memberPatrick Kalkman2-Mar-11 11:15 
Thank you alhambra.
GeneralMy vote of 5mvpMarcelo Ricardo de Oliveira28-Feb-11 8:45 
Hi Patrick
 
Good research and in-depth explanation on the subject, got 5 points from me Smile | :)
 
cheers,
marcelo
Take a look at Reactive Face Using Reactive Extensions here in The Code Project.

GeneralRe: My vote of 5memberPatrick Kalkman28-Feb-11 22:37 
Thank you Marcelo.
GeneralMy vote of 5memberYingbiao27-Feb-11 10:56 
Thank you
GeneralRe: My vote of 5memberPatrick Kalkman27-Feb-11 23:01 
Thank you for voting.

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

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