Two passwords … and lots of user IDs … towards OAuth 2.0

Outline

Identity 2.0
Identity 2.0

Over the past year or so, I have conducted many surveys at dissemination events, using wireless clickers to gather the results, where I ask attendees about how many usernames they had, and then on how many passwords they have. In every presentation I have made, the answer has been that they typically have between two and four passwords, but have more than 10 user IDs. This type of approach is unacceptable for the future, as we probably just need one ID, and it is the one that is the most trusted. A key concept is that users can start to define their own on-line identity and control the parts of it which are related to different contexts, as illustrated in Figure 1.

Within a highly trusted and secure environment, WS-* is the best framework to use to provide federated identity, but unfortunately it is extremely complex, and difficult to integrate with a wide range of system. The market is now focusing on a simpler method: OAuth 2.0. In order to demonstrate it, I’ve created a demo:

http://www.asecuritysite.com/id

Like it or not, the bigger hitters when it comes to Federated ID provision are Linkedin, Twitter, Microsoft, Facebook and Google. Each of these companies know the benefits of being the most trusted identity provider, as this will provide them with the opportunity to be the main focus for the user. Google and Microsoft typically focus on providing users with Cloud-based email accounts, which entice the user to you them, whereas LinkedIn, Twitter and Facebook aim to capture the user through their social networking activity. For this I’ve integrated the last ASP.NET MVC 4 integration of MVC 4, which provides for enhanced, and simplified, integration of OAuth 2.0:

http://asecuritysite.com/id/twitter

Federated ID
Federated ID

Figure 2 outlines how we can setup a trust infrastructure, where we can trust certain identity providers to prove the identity of a user. In this way we do not have to store the username and password ID. There are many identity providers which users use on a regular basis, and this is typically the account they remember best. Well-known providers who are supported in OAuth include Google, Facebook,  and Windows Live, with others such as Twitter and Linkedin providing API integration.

So what does the future hold? Well so many companies use their own in-house authorization system, where they register usernames and password, which can take a good deal of resources to setup and maintain. With a federated identity infrastructure, companies can define the identity providers they trust, and then use them to provide their identity. They will then get rights into the system based on the identity and their associated role.

OAuth 2.0

Image representing OpenID Foundation as depict...
Image via CrunchBase

OAuth has been defined as open standard for federated identity provision. It supports a login from an identity provider, without actually giving their username and password credentials, and uses user-agent redirections. Along with this it is complementary to OpenID.

OAuth 2.0 has evolved from the OAuth protocol (but is not backward compatible with OAuth 1.0). With OAuth 2.0 there is a much easier implementation on the client developer which improves the workflow for a range of access devices including desktops and mobile phones.

Key adopters of OAuth 2.0 have been Facebook, Microsoft and Google, who integrate with it in their APIs.

Outline Presentation

You will find the presentation on Federated ID in:

Source Code

Here’s my controller code for ASP.NET MVC 4:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using security.Models;
using System.Collections;
using System.Net;
using System.Text.RegularExpressions;
using System.IO;

using DotNetOpenAuth.Messaging;
using System.Web.Security;
using DotNetOpenAuth.OpenId.Extensions.AttributeExchange;

using DotNetOpenAuth.OAuth;
using Microsoft.Web.WebPages.OAuth;
using DotNetOpenAuth.AspNet;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration;
using DotNetOpenAuth.OpenId.RelyingParty;

namespace security.Controllers
{

    public class idController : Controller
    {
        private static OpenIdRelyingParty openid = new OpenIdRelyingParty();
        public IFormsAuthenticationService FormsService { get; set; }
        public IMembershipService MembershipService { get; set; }

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public void ExternalLogin(string provider, string returnUrl)
        {
            returnUrl = "http://asecuritysite.com";
            OAuthWebSecurity.RequestAuthentication(provider, Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
        }
        [AllowAnonymous]
       public ActionResult ExternalLoginCallback(string returnUrl = "")
        {
            AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
            if (!result.IsSuccessful)
            {
                ViewData["error"] = result.Error;
                return View("twitter", OAuthWebSecurity.RegisteredClientData);
            }

            //if (OAuthWebSecurity.Login(result.Provider, result.ProviderUserId, createPersistentCookie: false))
            //{
            //    return RedirectToLocal(returnUrl);
            //}

            //if (User.Identity.IsAuthenticated)
            //{
            //    // If the current user is logged in add the new account
            //    OAuthWebSecurity.CreateOrUpdateAccount(result.Provider, result.ProviderUserId, User.Identity.Name);
            //    ViewData["provider"] = result.Provider;
            //    ViewData["userid"] = result.ProviderUserId;
            //    return View("twitter");
            //}
            else
            {
                // User is new, ask for their desired membership name
                string loginData = OAuthWebSecurity.SerializeProviderUserId(result.Provider, result.ProviderUserId);

                OAuthAccount oAuthAccount = new OAuthAccount(result.Provider, result.ProviderUserId);

                UserModel user = new UserModel();

                var provider = result.Provider;
                var uniqueUserID = result.ProviderUserId;
                var uniqueID = provider + "/" + uniqueUserID;
          //      FormsAuthentication.SetAuthCookie(uniqueID, false);

                try
                {
                    var userDataFromProv = result.ExtraData;
                    if (userDataFromProv.Keys.Contains("email")) ViewData["email"] = userDataFromProv["email"];

                    if (userDataFromProv.Keys.Contains("country")) ViewData["country"] = userDataFromProv["country"];
                    if (userDataFromProv.Keys.Contains("accesstoken")) ViewData["accesstoken"] = userDataFromProv["accesstoken"];
                    if (userDataFromProv.Keys.Contains("firstname")) ViewData["firstname"] = userDataFromProv["firstname"];
                    if (userDataFromProv.Keys.Contains("lastname")) ViewData["id"] = userDataFromProv["lastname"];
                    if (userDataFromProv.Keys.Contains("id")) ViewData["id"] = userDataFromProv["id"];
                    if (userDataFromProv.Keys.Contains("name")) ViewData["name"] = userDataFromProv["name"];
                    if (userDataFromProv.Keys.Contains("link")) ViewData["link"] = userDataFromProv["link"];
                    if (userDataFromProv.Keys.Contains("gender")) ViewData["gender"] = userDataFromProv["gender"];
                    if (userDataFromProv.Keys.Contains("birthday")) ViewData["birthday"] = userDataFromProv["birthday"];
                    if (userDataFromProv.Keys.Contains("headline")) ViewData["headline"] = userDataFromProv["headline"];
                    if (userDataFromProv.Keys.Contains("summary")) ViewData["summary"] = userDataFromProv["summary"];
                    if (userDataFromProv.Keys.Contains("industy")) ViewData["industy"] = userDataFromProv["industry"];
                    if (userDataFromProv.Keys.Contains("location")) ViewData["location"] = userDataFromProv["location"];
                    if (userDataFromProv.Keys.Contains("description")) ViewData["description"] = userDataFromProv["description"];
                    if (userDataFromProv.Keys.Contains("url")) ViewData["url"] = userDataFromProv["url"];

                }
                catch (Exception)
                {
                }

                return View("twitter",OAuthWebSecurity.RegisteredClientData);
            }
        }

        private ActionResult RedirectToLocal(string returnUrl)
        {
            if (Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }
        public ActionResult twitter()
        {
            return View(OAuthWebSecurity.RegisteredClientData);
        }

    }
}

My cshtml code is:

 @using Microsoft.Web.WebPages.OAuth;
@model ICollection
 <h1>OAuth 2.0 (Twitter, Linkedin, and so on)</h1>
<p>This is a demo of OAuth. OAuth has been defined as open standard for federated identity provision. 
It supports a login from an identity provider, without actually giving their username and password credentials, and uses user-agent redirections. 
Along with this it is complementary to OpenID.</p>

<div>
        @using (Html.BeginForm("ExternalLogin", "id", new { ReturnUrl = ViewBag.ReturnUrl }))
        {
            @Html.AntiForgeryToken()
            <p>
                @foreach (AuthenticationClientData p in Model)
                {
                    @p.DisplayName
                }
            </p>
        }
    </div>
    <table>
    <tr><td>First name:</td><td>@ViewData["firstname"]</td></tr>
    <tr><td>Last name:</td><td>@ViewData["lastname"]</td></tr>
    <tr><td>Last name:</td><td>@ViewData["email"]</td></tr>

    <tr><td>Display name:</td><td>@ViewData["displayname"]</td></tr>

    <tr><td>Provider:</td><td>@ViewData["provider"]</td></tr>
      <tr><td>User ID:</td><td>@ViewData["userid"]</td></tr>

    </table>

You need register for an API key from identity providers, and added these in the AuthConfig.cs file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Web.WebPages.OAuth;
using security.Models;

namespace security
{
    public static class AuthConfig
    {
        public static void RegisterAuth()
        {

            OAuthWebSecurity.RegisterTwitterClient(
                consumerKey: "x",
                consumerSecret: "x");

            OAuthWebSecurity.RegisterFacebookClient(
                appId: "x",
                appSecret: "x");

            OAuthWebSecurity.RegisterGoogleClient();

            OAuthWebSecurity.RegisterLinkedInClient("x", "x");

            OAuthWebSecurity.RegisterMicrosoftClient(
              clientId: "x",
              clientSecret: "x");        }
    }
}

Registering for API Keys

In order to register the clients, you will have to register for an API key. The important ones are:

2 thoughts on “Two passwords … and lots of user IDs … towards OAuth 2.0

  1. Just desire to say your article is as astounding. The
    clarity in your post is just excellent and i can assume
    you’re an expert on this subject. Well with your permission let me to grab your feed to keep up to date with forthcoming
    post. Thanks a million and please keep up the gratifying work.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s