Friday, January 10, 2014

Securing ASp.Net Web API Service

Before Christmas I wrote an article on developing Services for Modern Application with ASP.Net Web Today, I want to pick up the topic again go deeper on making our service closer to production quality service.. Let’s get it started…

If you walked through my article and tried to create a Web API service, you will find it is almost effortless. well, there is a say goes this way “If it is too good to be true, probably it is” I find there are some wisdom in it.  the server we created is next to useless in production environment.  please hear me out on why I said that.

Imagine you put up this service in production on Internet, sure enough , your app can access it, but so does anybody on the internet!  and more over, that is a host of search engines like google, bing. They are working day and night sniff around on the internet. Do you mind they can hit your service to suck the data out from your system? do you want someone on the internet rage some kind of DOS attach on your site?

I am sure, you do not want any of these happen to you?  

so an unprotected site is never be good enough for live operation. The question put in front of us how to secure our Web API site?

Thanks to Microsoft, the solution is provided in Visual Studio.  When you start a new Web API project, you will see this screen:




If you are like me when I worked on it the first time, you would type the project name and click <Ok>. but slow down a bit, let’s take a closer look at this screen. on the low right portion of the screen, you see Authentication  No Authentication, and there is a button on top of it with the caption “Change Authentication”. let’s click on the button to see what we can get.

wow, it offers 4 different portions:

No Authentication :
default
Individual User Accounts:
for applications that store user profile in a SQL Server database, Users can register, or sign in using their existing account for Facebook, Twitter, Google, Microsoft or another provider.
Organization Accounts
for applications that authenticate users with AD, Window Azure AD or Office 365
Window Authentication
for Intranet Application

For an enterprise system, you most likely will go with  Organization Accounts or Window Authentication. For public facing application like ones in the Apple store, Google store or Microsoft store, you probably want to go with Individual User Accounts.

Let’s say we go with Individual Accounts.

You select Individual Accounts and clock on Ok button, then the IDE create the project for you as it did before. nothing special.

However, after the project is created you run your site and try to hit the site by http;//localhost://3593/api/Values

you will get “Authorization has been denied for this request”

if you go and take a closer look at the code the IDE generated, you will find 2 differences. one is there is attribute on the controller class

[Authorize]
public class ValuesController : ApiController


another one is you will see a new controller shown below:

[Authorize]
public class AccountController : ApiController


Another difference is not obvious, but very significant, that is the site come with a full function OAuth2 service implementation.  If you are interested, you can search for OAuth2 on the web, you can get tons of information….

That means the site is protected! That ‘s a good sign, but how to access it?  If you are doing “single Page “ Web project,  Microsoft gives you all the code to access the site as part of project template, all you need to do is provide the site base address. If you are working on Windows Store app or desktop app you need to code yourself.  Leaving the easy thing aside, let me touch on the details in Windows Store App / desktop app.   The code I am going to show you here are from Windows Store App, but it will be same if it is form a desktop app, basically, it access the site through HttpClient class.

In order to access the site, you need to have an account on the site, you can register an account with the site by hitting the AccountController.


the following code is used to register an  internal account

  public async Task<bool> Register(AccountRegistation registation)
       {
            Client = new HttpClient();
            Client.BaseAddress = new Uri(baseAddress);
            Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
           HttpResponseMessage response = await Client.PostAsJsonAsync<AccountRegistation>( "api/Account/Register", registation);

           return response.IsSuccessStatusCode;
       }

and AccountRegistation is a data class show below:

public  class AccountRegistation
    {
       public string UserName { get; set; }
       public string Password { get; set; }
       public string ConfirmPassword { get; set; }

    }


once you register an account with the site, you can  hit the OAuth2 service to get security token, the code for that is similar to the code below:

   public async Task<BearerToken> RequestToken(Credential credential)
       {
           var response = await Client.PostAsync(Token, credential.StringContent);
           var tokenResponse =   await response.Content.ReadAsAsync<BearerToken>();
           return tokenResponse;
       }

where  BearerToken and   Credential are the data class shown below :

    public class BearerToken
    {
        [DataMember(Name = "access_token")]
        public string AccessToken { get; set; }

        [DataMember(Name = "token_type")]
        public string TokenType { get; set; }

        [DataMember(Name = "expires_in")]
        public int ExpiresIn { get; set; }

        [DataMember(Name = "userName")]
        public string UserName { get; set; }

        [DataMember(Name = ".issued")]
        public DateTime Issued { get; set; }

         [DataMember(Name = ".expires")]
        public DateTime Expires { get; set; }
    }


public class Credential
    {
       public GrantType GrantType { get; set; }
       public string UserName { get; set; }
       public string Password { get; set; }
    }



Once you have the token, you can put the token on the request before you hit the Values controller. the code for that is similar to the following:

  token = await SpellingServiceProxy.RequestBearerToken(TestSettings.OAuthServiceBaseAddress);

         SpellingServiceProxy proxy = new SpellingServiceProxy("http://localhost:1234", token);
         IList<Product> result = await proxy.RetrieveCatalogAsync();


This is just introduction. OAuth 2 is a big topic by itself.  Account Controller could be another topic by itself. With Account Controller you can do the following:

Register internal user account
Register External user account
login and logout
manage account info
Change password
Set password
Add External Login
Remove Login
ExternalLogin / Logout

2 comments:

  1. Hi Lu... i'm going crazy to find some example/walkthrough about using "Register External user account"... can you help me? thanks in advance

    ReplyDelete
  2. this will be in my next iteration. I will publish the result when I figure it out.... if you figured it out before I do, please share your findings with me,

    ReplyDelete