DCSIMG
February 2009 - Posts - Itai Goldstein

February 2009 - Posts

How To: Implement HMAC Authentication On a RESTful WCF Service

There are several approaches in implementing authentication in RESTful WCF services. Using SSL and Digest Authentication are two options, while in this post I would like to demonstrate another approach which uses HMAC (Hash Message Authentication Code) in order to achieve both message authentication and integrity.

In this approach the server provides the client an ID and a secret key through some technique (e.g. sending an email containing the ID and the secret key) which will be used by the client to sign all his requests.

A secret key can be generated in the following way:

byte[] secretkey = new Byte[64]; RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); rng.GetBytes(secretkey);

This post will not cover what is a RESTful service and how should we implement all it’s properties in WCF, for this purpose you can refer to this great article which I used in my research prior to this post.

In our example the service will provide specific user’s bookmarks to its consumer. In order to consume this service, a requester must provide some hashed message (in our case – the request Uri encrypted with the secret key) in the request header authorization property (different implementations of the client would be provided in future posts).

So without further ado's, this is the service contract method definition:

[WebGet(UriTemplate = "users/{username}/bookmarks?tag={tag}")] [OperationContract] Bookmarks GetUserBookmarks(string username, string tag);

The contract enforces us to use the specified Uri template which implies that for a specific username (the requested user) and specific tag filter, the requester will be provided with a bookmarks list matching this criteria.

Here is the service method implementation:

public Bookmarks GetUserBookmarks(string username, string tag) { WebOperationContext context = WebOperationContext.Current; OutgoingWebResponseContext outgoingResponseContext = context.OutgoingResponse; bool isUserAuthenticated = IsUserAuthenticated(username); if (isUserAuthenticated == false) { outgoingResponseContext.StatusCode = HttpStatusCode.Unauthorized; return null; } outgoingResponseContext.StatusCode = HttpStatusCode.OK; Bookmarks bookmarks = new Bookmarks(BookmarksProvider.GetUserBookmarks(username, tag)); return bookmarks; }

The simple implementation I used here suggests that the request is being checked for its user’s authentication: if the authentication fails, the requester will be responded with Unauthorized HTTP status code (401) and no bookmarks. If the authentication succeeds – the bookmarks list is provided along with OK HTTP status code (200).

I’ve skipped the BookmarksProvider.GetUserBookmarks method implementation due to it’s irrelevancy for this post subject.

Here is my implementation for the IsUserAuthenticated method:

private bool IsUserAuthenticated(string username) { WebOperationContext context = WebOperationContext.Current; IncomingWebRequestContext incomingRequestContext = context.IncomingRequest; string requestUri = incomingRequestContext.UriTemplateMatch.RequestUri.ToString(); string authorizationHeader = incomingRequestContext.Headers[HttpRequestHeader.Authorization]; string authenticationToekn = string.Format("{1}{0}{2}", Delimeters.FirstClassDelimeter, authorizationHeader, requestUri); byte[] userKey = GetUserKey(username); bool isValidHash = Authentication.ValidateHash( userKey, authenticationToekn, Delimeters.FirstClassDelimeter, UTF8Encoding.UTF8); return isValidHash; }

This method composes an authentication token (this is a pure implementation step – it is up to the server to decide it’s protocol – and up to the client to obey in order to consume..) from the request Uri and the hashed authorization header. Then the authentication token is being validated along with the current requester secret key (fetched by the GetUserKey method) through the Authentication.ValidateHash method:

public static bool ValidateHash(byte[] key, string message, string delimeter, Encoding encoding) { HMACMD5 hmacMD5 = new HMACMD5(key); string[] messageParts = message.Split(new string[] { delimeter }, StringSplitOptions.RemoveEmptyEntries); if (messageParts == null || messageParts.Length < 2) { return false; } string encodedText = messageParts[0]; string text = messageParts[1]; byte[] textBytes = encoding.GetBytes(text); byte[] computedHash = hmacMD5.ComputeHash(textBytes); string computedHashString = Convert.ToBase64String(computedHash); return encodedText.Equals(computedHashString); }

In the validation method, the authentication token is being split to the message and hashed message parts – in our case, it’s the request Uri and the request Uri hashed using the requester’s secret key. After the parts are split, the secret key is being used to generate the hashed message (using the HMACMD5 class) again in order to be compared to the received hashed message. If the hashed messages are equal then the authentication is ok, otherwise it is invalid.

There are several ways to consume this service. In this post I’ll go over one of them in which a console application consumes our service:

byte[] key = GetUserKey(); string uri = "http://localhost:4609/ServiceHost/BookmarksService.svc/users/itai/bookmarks?tag=News"; HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest; string encodedUri = Authentication.EncodeText(key, uri, UTF8Encoding.UTF8); request.Headers[HttpRequestHeader.Authorization] = encodedUri; HttpWebResponse response = request.GetResponse() as HttpWebResponse; Stream bookmarksStream = response.GetResponseStream(); StreamReader reader = new StreamReader(bookmarksStream); string str = reader.ReadToEnd(); reader.Close(); bookmarksStream.Close();

As you can see for yourself, this client is rather simple: prepare the request object using service Uri and define the authorization header using the client secret key to hash the message (in our case it is the request Uri), then send the request and parse the response (XML formatted).

Here is Authentication.EncodeText method implementation:

public static string EncodeText(byte[] key, string text, Encoding encoding) { HMACMD5 hmacMD5 = new HMACMD5(key); byte[] textBytes = encoding.GetBytes(text); byte[] encodedTextBytes = hmacMD5.ComputeHash(textBytes); string encodedText = Convert.ToBase64String(encodedTextBytes); return encodedText; }

And here are our client results:image

Summary 

In this post I’ve implemented a RESTful WCF service which is protected by HMAC authentication token which is being passed in the service request header by a simple service consumer.

In my upcoming posts, I’ll review another different client implementations – stay tuned..

Hope you’ll find it useful.

References:

A Guide to Designing and Building RESTful Web Services with WCF 3.5

HMACMD5 at MSDN

Posted by itai | 8 comment(s)

Configuration shortcuts (or IntelliSense for configuration file)

The configuration appSettings & connectionStrings sections are highly used in our daily application development.

<appSettings> <add key="ApplicationName" value="ConfigurationShortcutsSample"/> </appSettings>

The way we usually access the values which are stored within these sections is through the ConfigurationManager class when we specify the section key string:

string applicationName = ConfigurationManager.AppSettings [AppSettingsKeys.ApplicationName];

This methodology could lead us developers to mistakes which can be detected only at runtime in case we mistyped the application setting key string.

I would like to offer another way of accessing these sections which will prevent us from mistyping the application setting key and even provide sort of IntelliSense.

In this way, we need to write a static class which will hold the keys for our configuration section keys in static properties:

public static class AppSettingsKeys { public static string ApplicationName { get { return "ApplicationName"; } } }

That’s it.. now we can access our configuration application settings keys with the help of our static class:

image

Summary

In this post I reviewed a way to have shortcuts to our configuration file appSettings & connectionStrings sections which can act as IntelliSense and prevent us from coding mistakes which can be detected only on runtime.

Hope you’ll find it useful.

Posted by itai | 2 comment(s)
תגים:, , ,

Redirecting on a callback

In one of my previous posts, I reviewed a way to handle client side events on the server side by using the Callback feature of ASP.NET 2.0.

But what about redirecting from the current page when you handle the client event?

You’ll find that it is not possible: “Response.Redirect cannot be called in a Page callback.” or “Server.Transfer cannot be called in a Page callback.” messages will appear in case you’ll use Response.Redirect or Server.Transfer operations

In order to redirect to another page at the end of your flow, you’ll have to do it in the client side callback handler which was defined at the ClientScriptManager.GetCallbackEventReference method:

Redirecting on a callback 

Hope you’ll find it useful.

Improve your ASP.NET Website User Experience: Flush Down your partial Response

There are times when your website page needs to do some heavy work on the server side and you don’t want your user to wait till the work is complete to get a response.

In these cases you can use the Response.Write & Response.Flush methods, and here is a short example (on the HTML source side):

        <% Response.Write("1st response..."); %>
        <% Response.Flush(); %>
        <% System.Threading.Thread.Sleep(2000); %>
        
        <% Response.Write("2nd response..."); %>
        <% Response.Flush(); %>
        <% System.Threading.Thread.Sleep(2000); %>
        
        <% Response.Write("3rd response..."); %>
        <% Response.Flush(); %>
        
        <% Response.Write("4th response..."); %>
        <% Response.Flush(); %>

When you’ll run this code, you’ll find that the page is loaded with “1st response…” message, after 2 more seconds, the “2nd response…” would popup, and after 2 more seconds, the last two messages would appear.

This means that we can show our website users some response while our server doing some work.

This will work also on the code-behind, but needs a little tweak..

    Response.Write("1st response...");
    Response.Flush();
    Response.Flush();
    System.Threading.Thread.Sleep(2000);
    Response.Write("2nd response...");
    Response.Flush();
    Response.Flush();
    System.Threading.Thread.Sleep(2000);
    Response.Write("3rd response...");
    Response.Flush();
    Response.Write("4th response...");
    Response.Flush();

You probably notice that each Response.Flush appear twice, this is not a mistake - The reason is that sometimes when “you have to use more than a handful of toilet paper, it’s best to flush twice”..

Hope you’ll find it useful.

Posted by itai | 10 comment(s)

Quince - User Experience Design patterns Exploration Tool

There is no need to break your head each time you try to find the best way to design your application user interface in order to provide the best user experience to your application users.

You can check out the Infragistics Quince which is a User experience (UX) patterns exploration tool.

There are different ways to find the pattern you are looking for:

Here is exploring all patterns method:

image

And here is exploring by tag relations method:

image

And the pattern description screen is very intuitive:

image

You can check out this blog post, which introduces this tool.

Hope you’ll find it useful.

Posted by itai | 2 comment(s)

T-SQL Split function

During one of the projects I worked on, I had to parse a text which was passed from the application in my T-SQL code. I found that T-SQL had no built-in string system function for this operation, which I find rather useful, especially in cases you need to perform some batch based operations (which helps accelerate your application performance by reducing round trips to the DB).

So I came up with the following solution:

CREATE FUNCTION [dbo].[Split]
(    
    @RowData NVARCHAR(MAX),
    @Delimeter NVARCHAR(MAX)
)
RETURNS @RtnValue TABLE 
(
    ID INT IDENTITY(1,1),
    Data NVARCHAR(MAX)
) 
AS
BEGIN 
    DECLARE @Iterator INT
    SET @Iterator = 1

    DECLARE @FoundIndex INT
    SET @FoundIndex = CHARINDEX(@Delimeter,@RowData)

    WHILE (@FoundIndex>0)
    BEGIN
        INSERT INTO @RtnValue (data)
        SELECT 
            Data = LTRIM(RTRIM(SUBSTRING(@RowData, 1, @FoundIndex - 1)))

        SET @RowData = SUBSTRING(@RowData,
                @FoundIndex + DATALENGTH(@Delimeter) / 2,
                LEN(@RowData))

        SET @Iterator = @Iterator + 1
        SET @FoundIndex = CHARINDEX(@Delimeter, @RowData)
    END
    
    INSERT INTO @RtnValue (Data)
    SELECT Data = LTRIM(RTRIM(@RowData))

    RETURN
END

Note that this implementation uses DATALENGTH function instead of the LEN function, and that is due to the fact that LEN doesn’t consider the leading spaces in the given string variable – this can harm the parsed result. Another difference between DATALENGTH and LEN is that DATALENGTH returns the result as the number of bytes used where LEN returns the result as number of characters, and that is the reason we should divide the DATALENGTH result with 2.

Here is an example of how to use the Split function:

DECLARE @Str NVARCHAR(MAX)
SELECT @Str = 'This#$#is#$#my#$#test'

SELECT *
FROM   [dbo].[Split] (@Str, '#$#')

And here are the results:

 image

Summary

In this post I reviewed my implementation for T-SQL string Split function which you may find useful when parsing strings in T-SQL, especially in cases you would like to improve your application performance by doing some batch based operations.

Hope you’ll find it useful.