← Back to overview
November 25, 2011 · Belgian eID Windows Identity Foundation

The Belgian eID in Windows Azure – Part 1: Authentication and Identification for your webroles with the eID IdP

If you follow my other blog you might have noticed that I'm really into the Belgian eID. Needless to say I had to look at how we can use the Belgian eID in Windows Azure. In this series I'll show you how you can integrate it with your existing or future cloud projects.

We'll start by taking a look at the eID Identity Provider (or eID IdP), an open source project hosted on code.google.com: http://code.google.com/p/eid-idp/. The IdP runs in JBoss and uses a relational database (like MySQL, PostgreSQL, …). To keep things simple, we won't be looking at how you can install the IdP.

Besides running the eID IdP yourself, you can also use the hosted version on the e-Contract website (managed by Frank Cornelis, one of the contributors of the eID IdP project). The following page shows the supported protocols: https://www.e-contract.be/eid-idp/main

Since we're going to use Windows Identity Foundation, these metadata endpoints seem to be the most appropriate:

If you look at the claims offered by the WS-Federation Authentication and Identification endpoint, it seems we can get access to some useful information:

schemas.xmlsoap.org/ws/2005/05/identity/claims/name  
schemas.microsoft.com/ws/2008/06/identity/claims/role  
schemas.xmlsoap.org/ws/2005/05/identity/claims/surname  
schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname  
schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier  
schemas.xmlsoap.org/ws/2005/05/identity/claims/streetaddress  
schemas.xmlsoap.org/ws/2005/05/identity/claims/locality  
schemas.xmlsoap.org/ws/2005/05/identity/claims/postalcode  
schemas.xmlsoap.org/ws/2005/05/identity/claims/gender  
schemas.xmlsoap.org/ws/2005/05/identity/claims/dateofbirth  
be:fedict:eid:idp:nationality  
be:fedict:eid:idp:pob  
be:fedict:eid:idp:photo  
be:fedict:eid:idp:age  

Enough chitchat, show me some code!

Setting up the web application

We're going to build a webrole that will use the eID IdP for authentication and identification. To build this application you'll need the Azure SDK, ASP.NET MVC3, the WIF SDK and the WIF runtime:

Create a new Windows Azure project, add an ASP.NET MVC 3 web role and choose the Internet Application template. Now if you run the application and you'll see that you can view the application without having to login, but this isn't what we want. We would like to have an application that requires you to login using the eID IdP. This way we'll know the user is authenticated without having to do the management of usernames, passwords, security, … And we're actually externalizing the authentication.

Now right click the webrole and choose Add STS reference, fill in the application URI (in our case this is http://127.0.0.1 – this is the address that was assigned by the devfabric). Choose to use an existing STS: https://www.e-contract.be/eid-idp/endpoints/ws-federation/metadata/auth-ident-metadata.xml, this endpoint will authenticate you (by asking your pincode) and identify you (get your information).

To get things working you'll need to disable the request validation mode (see my previous post):

<httpRuntime requestValidationMode="2.0"/>  

Claims! Claims! Claims!

Before we can run the application we'll write some code to make everything go well and to display the claims we received from the eID IdP. It's important to know that this IdP uses the realm URI as the return URL after a successful login. This means if you used http://127.0.0.1 as realm, you'll be redirected here. But this isn't what we want…

What we want is that the user gets redirected to an action like /Account/Display after a successful login (to show the user's claims). To achieve this you'll need to add the following code in the Global.asax file:

protected void Application_Start()  
{
    ...
    FederatedAuthentication.ServiceConfigurationCreated += OnServiceConfigurationCreated;
}

private void OnServiceConfigurationCreated(object sender, ServiceConfigurationCreatedEventArgs e)  
{
    FederatedAuthentication.WSFederationAuthenticationModule.SignedIn += new EventHandler(WSFederationAuthenticationModule_SignedIn);
}

private void WSFederationAuthenticationModule_SignedIn(object sender, EventArgs e)  
{
    HttpContext.Current.Response.Redirect("/Account/Display");
}

Ok this is a good starting point. Now, after a successful login, the user will be redirected to /Account/Display. This means we'll need to write the required code in the AccountController. Let's start with some helper functions that will allow us to get all the claims available for the current identity and an other function that will help us read the value for a specific claim:

private ClaimCollection GetClaims()  
{
    var claimsPrincipal = Thread.CurrentPrincipal as IClaimsPrincipal;
    var claimsIdentity = (IClaimsIdentity)claimsPrincipal.Identity;
    return claimsIdentity.Claims;
}

private string GetClaimValue(ClaimCollection claims, string claim)  
{
    var claimRecord = claims.FirstOrDefault(o => o.ClaimType == claim);
    if (claimRecord != null)
        return claimRecord.Value;
    else
        return null;
}

Now with this code it will become very easy to write the required actions: Display and Photo. This Display action maps the claims to the UserInfo model and displays it in the view:

public ActionResult Display()  
{
    var claims = GetClaims();

    var user = new UserInfo();
    user.NameIdentifier = GetClaimValue(claims, "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier");
    user.Name = GetClaimValue(claims, "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name");
    user.StreetAddress = GetClaimValue(claims, "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/streetaddress");
    user.Nationality = GetClaimValue(claims, "be:fedict:eid:idp:nationality");
    user.POB = GetClaimValue(claims, "be:fedict:eid:idp:pob");
    user.Locality = GetClaimValue(claims, "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/locality");
    user.Surname = GetClaimValue(claims, "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname");
    user.Gender = GetClaimValue(claims, "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/gender") == "1" ? "Male" : "Female";
    user.GivenName = GetClaimValue(claims, "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname");
    user.DateOfBirth = GetClaimValue(claims, "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/dateofbirth");
    user.PostalCode = GetClaimValue(claims, "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/postalcode");
    user.Age = GetClaimValue(claims, "be:fedict:eid:idp:age");
    user.AuthenticationMethod = GetClaimValue(claims, "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod");
    return View(user);
}

In the Display view we'll simply show all properties of the model, but we'll also show something else…

<img style="float: right;" src="/Account/Photo" alt="" width="140" height="200" />  

Yes… that's right. We'll show the user's photo. One of the claims is the be:fedict:eid:idp:photo claim. This claim contains your picture encoded using standard Base64 encoding. And knowing this makes it very easy to build the Photo action:

public ActionResult Photo()  
{
    var photo = GetClaims().FirstOrDefault(o => o.ClaimType == "be:fedict:eid:idp:photo");
    if (photo != null)
    {
        var stream = new MemoryStream(Convert.FromBase64String(photo.Value));
        return new FileStreamResult(stream, "image/jpg");
    }
    else
    {
        return new EmptyResult();
    }
}

The result

When you start the application, you'll be redirected to the eID IdP:

After entering the PIN code the Java applet will start reading the eID and the eID IdP will redirect to the realm URI (in this case 127.0.0.1). Since we made that small change in the Global.asax file we'll be redirected to /Account/Display after a successful login:

Download the code: waz-eid-part1.zip

Enjoy!

  • LinkedIn
  • Tumblr
  • Reddit
  • Google+
  • Pinterest
  • Pocket
Comments powered by Disqus