Running YetAnotherForum inside Sitecore

As I mentioned in the previous post, YetAnotherForum (YAF) cannot run inside Sitecore unless the code base of YAF is changed. So that’s exactly what I did. 

YetAnotherForum running in Sitecore

YetAnotherForum running in Sitecore

 You can find the changed YAF codebase in Sitecores trac:

http://trac.sitecore.net/YAFIntegration

So what does the code do? It allows you to run YAF in a Sitecore layout, on any Sitecore page you wish, using Sitecore extranet (or any other domain) users.

But let’s begin with the beginning. In order to run YAF inside a Sitecore web site at all, major changes are required in the web.config of your website. Basically it requires you to merge the YAF config files with the Sitecore config files. I have provided a sample web.config where I have merged the 2 config files together, as well as a complete description of all changes required.

After you have merged the web.configs, you will need to build the code and apply the code and binaries to the Sitecore solution. The documentation will help you with this.

What code changes have been made then? Since Sitecore and YAF both uses standard .net security providers, changes are relatively small (although widespread). YAF is capable of digesting Sitecore members and roles (users and groups) directly. But since the .net platform only allows one profile provider, the YAF profile provider need to inherit from Sitecore’s profile.

Another change are also implemented: The standard .net security model expects all users to have access to all parts of the website. Sitecore cannot live with that, as some users can access the client, and other can access the extranet. Sitecore deals with this issue in a brilliant, simple way, by prefixing users with the Sitecore domain name. So when Sitecore returns the Anonymous user, the username is extranet\Anonymous. To avoid displaying user names prefixed with the current domain name in YAF, the code wraps the MembershipUser class to ensure that only users from the current domain (usually extranet) can log into YAF, and that the domain name is not displayed in the username.

Users from the current Sitecore domain is displayed in YAF.

Users from the current Sitecore domain is displayed in YAF.

Since YAF is licensed under the GNU public license, so is this code. This means that you can use, change and share the code and any changes you make, as you wish.

 

Using Sitecore users in YetAnotherForum

YetAnotherForum (or YAF for short) is an open source discussion forum written in C# and .NET. Sitecore and YAF cannot run in the same IIS application (they can, if you change the YAF source code, which I will show in a later post), but with a little piece of open source code you are able to use the Sitecore users in YAF.

The open source code is available at:

http://trac.sitecore.net/YAFSingleSignon

The idea is to have Sitecore and YAF running in the same second-level domains: For example let your Sitecore website run at www.mysite.com and YAF in forum.mysite.com.
When users log into the Sitecore extranet, the user information is stored in a cookie which is then digested by YAF.

First you will need to download the code from http://trac.sitecore.net/YAFSingleSignon and build it yourself.

Copy the YAFLogin.dll to your Sitecore /bin/ folder. Then copy the YAFLogin.dll and SitecoreLogin.dll to the YAF /bin/ folder. Also copy the /sitecorelogin/default.aspx page to YAF.

In order to save the extranet credentials, you must apply the following 2 lines of code to your Sitecore extranet login dialog:

// Create a SitecoreUser by logging into the Sitecore extranet
// and retrieve the user information
SitecoreUser user = SitecoreUser.Login(eUserName.Text, ePassword.Text, chkRememberMe.Checked);
// Store the SitecoreUser as a cookie. This cookie can be retrieved by YAF.
user.Store();

That’s it. The user information is persisted in a cookie which can be digested by YAF, as cookies can be shared across second-level domains. There are 2 methods of digesting the Sitecore extranet user. The first method is to call the /sitecorelogin/default.aspx page which will create the user in YAF (if not already existing) do a login a redirect to the default YAF page. The second method is to extend the default.aspx page of YAF with the following code:

protected void Page_Load(object sender, EventArgs e)
{
  try
  {
    // Restore the sitecore user from the persistant storage (the cookie)
    YAF.Sitecore.PersistenceManager manager = new YAF.Sitecore.PersistenceManager();
    YAF.Sitecore.SitecoreUser user = manager.Restore();
    if (user != null)
    {
      // Instantiate the login manager and log the Sitecore user into YAF
      YAF.Sitecore.LoginManager loginManager = new YAF.Sitecore.LoginManager();
      loginManager.Login(user);
      // The SitecoreUser is now logged in, and the cookie can be removed
      manager.Delete();
      // Load same page to let YAF read the session
      Response.Redirect(Request.RawUrl,false);
    }
  }
  catch (Exception ex)
  {
    Response.Write("Failed to login Sitecore Extranet user: " + ex.Message);
  }
}

This code does the same as the /sitecorelogin/default.aspx but will be executed by every page in YAF you call.

You can read more about the source code at http://trac.sitecore.net/YAFSingleSignon/browser/Trunk/Sitecore.YAF.docx

Check whether client’s browser have cookies enabled

Usually we assume that every user have cookies enabled. I cannot find any stats on the number of users who have disabled cookies, but 94% of all browsers have Javascript enabled, so lets assume that en equal number have cookies enabled (I know that the remaining 6% could easily be web crawlers).

What should we do with the remaining 6% then? If the website uses cookies as a shopping basket, it would be a good service to let the user know that he is not able to shop without enabling cookies.

When first investigatig this, I assumed that a server-side solution existed. So I implemented the following code in c#:

if (Request.Browser.Cookies) 
  Response.Write("Your browser supports cookies. You may shop");
else
  Response.Write("The Browser does not support Cookies. Shopping is not possible.");

Unfortunately this tells me if the browser as such supports cookies, not that cookies are enabled by the user. When using IE7, the code always returns true, since IE7 supports cookies in general. Disabling cookies in IE7 changes nothing.

I used Google to search for the answer, and unfortunately you need to use Javascript to check if the user have enabled cookies in his browser. This website contains the Javascript to use.

I rewrote the Javascript so it writes some text if cookies are enabled, and another text if not:

function CookieSetText(yesText, noText)
{
  var cookieEnabled=(navigator.cookieEnabled)? true : false
  //if not IE4+ nor NS6+
  if (typeof navigator.cookieEnabled=="undefined" && !cookieEnabled)
  {
    document.cookie="testcookie"
    cookieEnabled=(document.cookie.indexOf("testcookie")!=-1)? true : false
  }
  if (cookieEnabled)
    document.write(yesText);
  else
    document.write(noText);
}

 When adding a reference to the script in my HTML header, I can use it from my Sitecore XSLT’s:

<script type="text/javascript">
  CookieSetText('<sc:text field="CookiesEnabled"/>', '<sc:text field="CookiesDisabled"/>');
</script>

Th example above writes the text for the current item’s “CookiesEnabled” field if cookies are enabled, or writes from the “CookiesDisabled” field when cookies are disabled.