I’m involved with all of our major clients at Avantime and pretty much all of them are now starting to mention that they would like to include social networking in their intranets etc. Everyone is of course referring to Facebook and wants “their own Facebook”. There are few products available for social networking and even fewer free products.

KickApps.com is a free white label SaaS community platform. Free in the sense that you have to accept advertising on your site or pay to remove it. It’s not Facebook, but it’s the best free platform I’ve seen for social networking. Compared to Ning, Kickapps is awesome. Here’s how KickApps describe themselves:

KickApps provides brands, enterprises and web publishers with solutions that enable them to create and manage next generation web experiences that are social, interactive, dynamic, distributed, and data-informed. KickApps solutions consist of a suite of hosted social and media applications and services that are used by some of the world’s largest websites and brands to grow & engage their on line audiences and foster deeper relationships with customers.

Customers include HBO, National Geographic, Johnson & Johnson, Kraft etc.

KickApps has good features for integrating their platform with any existing platform. Most importantly they support DNS masking and SSO (single sign on). In this post I explain how KickApps SSO is implemented and how you can benefit from it with EPiServer.

KickApps SSO sequence explained

Below is a visualization of how the SSO works. It’s not a complex or technically advanced solution but it’s still pretty secure and gives you great flexibility to control access for members of your existing platform. Why isn’t it secure you might ask? I’ll get to that soon.

kickapps-sso-visualized

KickApps simply re-direct an anonymous user to a URL defined in your KickApps site configuration and let the existing platform authenticate or register the user. KickApps web service returns a session token and transaction id that when passed to KickApps as query string parameters work as credentials for the given user. This would be secure if KickApps also supported SSL, which they don’t. Someone sniffing the network could easily use the session token and transaction id to get into KickApps. However, no passwords are ever sent and you probably don’t have your business secrets there anyways so  in my opinion this is acceptable.

Methods available in KickApps SSO SOAP API

  • Member Join and Register
  • Combined Member Sign On and Register
  • Member Sign On
  • Member Sign Out
  • Member Change Username
  • Member Change Email
  • Member Profile Edit and Update

All of them are implemented in my library. Documentation at KickApps:
KickApps SSO Integration guide | SOAP SSO API Reference

SSO Plugin for EPiServer?

EPiServer - KickApps ssoKickApps provide plug-ins for platforms such as Joomla, WordPress and Drupal. They also provide a sample helper class for .NET  that wrap around their SOAP web service. With the recent update of KickApps to 4.0 that helper class stopped working because the web service interface changed. In my library I added the web service reference as usual but made changes to the generated proxy code to support the custom SOAP header. I’ve put comments with every change so you can re-create the web service proxy if the interface changes in the future. I’ve wrapped some of the functionality in their helper class in my library but simplified the methods.

The SSO API doesn’t depend on EPiServer and could easily be used with any .NET platform and that’s why I’ve separated the EPiServer code.
The implementation for EPiServer is done in the login and logout page. Authentication is still handled by the underlaying providers in EPiServer, what’s different is authenticating users against KickApps. When authenticating a user against KickApps we receive two things: a session token and a transaction id (see the authentication sequence above). These two things must be appended to KickApps URL’s to identify the user, so if you want to embed KickApps’ widgets on your site that show user specific information you need to store them for the duration of the session.

Two login scenarios

We need to detect if the user is redirected from KickApps which is easily done by looking at the query string parameter. Credentials are always verified against the MembershipProvider configured for EPiServer and if successful we can control whether to create an account for the user and or update the users meta data (phone number, name etc) before redirecting back to KickApps with the session token and transaction id in the query string.

If the user is logging into EPiServer directly we cannot redirect the user to KickApps, that would confuse the user, no doubt. So we need to embed a resource on the landing page in EPiServer that point to KickApps so the users’ browser connect to KickApps and authenticate there.

For simplicity I’ve implemented KickApps SSO on the login page that comes with the EPiServer sample site. The code below creates and/or authenticates a user against KickApps, it’s attached to the OnLoggedIn event of the Login control. You find the complete aspx and code at the end of this post.

protected void OnLoggedIn(object sender, EventArgs e)
{
    // The sender is the login control
    System.Web.UI.WebControls.Login loginCtrl = sender as System.Web.UI.WebControls.Login;
 
    // Load the users profile
    EPiServerProfile userProfile = EPiServerProfile.Get(loginCtrl.UserName);
 
    // Make sure the user has a profile
    if (userProfile != null)
    {
        // If the user is already registered with KickApps we've stored that
        // in his profile (see below)
        if ((Boolean)userProfile["HasKickApps"] == true)
        {
            // Instanciate a new KickApps object. The string argument refers to
            // your web.config setting containing the credentials for your Kickapps site
            KickApps ka = new KickApps("KickAppsCrendentials");
 
            KickAppsResponse response = ka.SignInUser(userProfile.UserName, userProfile.EmailWithMembershipFallback);
 
            if (response.Successful)
            {
                // Store the session token and transaction id in the session so
                // we can use it later on for this user.
                Session.Add("KickAppsSessionToken", response.SessionToken);
                Session.Add("KickAppsTransactionId", response.TransactionId);
            }
            else
            {
                // Handle problems here
                string status = response.Status;
            }
        }
        else
        {
            KickApps ka = new KickApps("KickAppsCrendentials");
 
            // Kickapps require a birthdate and a user must be older than 13 years to
            // register.
            KickAppsResponse response = ka.SignInRegisterUser(userProfile.UserName,
                userProfile.EmailWithMembershipFallback, userProfile.FirstName,
                userProfile.LastName, "1900-01-01", KickApps.Gender.Unknown);
 
            if (response.Successful)
            {
                // Store information in the users' profile.
                userProfile["HasKickApps"] = true;
                userProfile["KickAppsUserID"] = response.UserId;
                userProfile.Save();
 
                // Store the session token and transaction id in the session so
                // we can use it later on for this user.
                Session.Add("KickAppsSessionToken", response.SessionToken);
                Session.Add("KickAppsTransactionId", response.TransactionId);
            }
            else
            {
                // Handle problems here
                string status = response.Status;
            }
        }
    }
}

Logging out

protected void OnLoggedOut(object sender, EventArgs e)
{
    // If the session contains KickApps credentials the user must have been authenticated
    // there and we better sign them out by redirecting them to the logout page of KickApps
    if (Session["KickAppsSessionToken"] != null && Session["KickAppsTransactionId"] != null)
    {
        // Abandon the session, we won't need it now that the user is signed out
        Session.Abandon();
 
        // Redirec to the logout page. The "as"-querystring must be subsituted against your own
        // site id. The url "kickapps.corelocation.se" must be substituted with your own site url
        Response.Redirect("http://kickapps.corelocation.se/kickapps/user/logoutUser.kickAction?as=101640");
    }
}

My KickApps site is configured for DNS masking and the URL’s in the code point to my site. You do need to change these url’s into your own. The query string parameter “as” is YOUR KickApps site id. If you wonder why www.corelocation.se and the KickApps site doesn’t work it’s because the EPiServer site is running on my MacBook and points to my IP at home. For obvious reasons I bring my computer to work.

The code

Download KickAppsSSOLibrary for .NET

Download Login/Logout template for EPiServer

Related posts