Wednesday, March 31, 2010

Installing the TC Integration Module 1.1

In my last post I provided an overview of the Telligent Community integration module for Sitecore. While the module comes with a lot of documentation - including instructions on how to install the module - sometimes it's helpful to have someone guide you through the process. That's what I'm going to do.

TC integration module architecture
Before I get into the actual installation instructions, it's important to understand what you're going to install. I will explain each section when I get to it, but here's a quick overview:
  • Authentication is handled by Sitecore using ASP.NET forms authentication.
  • Sitecore is responsible for creating an authentication cookie that TC uses to provide single sign-on.
  • Sitecore passes user information to TC so TC knows which roles the user has been assigned to.
  • TC content is exposed to Sitecore through a REST API.
  • Additions to the Sitecore client are installed using a Sitecore package.
Pre-requisites
Before you attempt to install the TC integration module version 1.1, be aware of the following:
  • You must be running Sitecore 6.1 or 6.2.
  • You must be running Telligent Community 5.0 SP1. Version 5.5 might work, but I haven't tested it to know for sure.
  • Sitecore and Telligent Community must be running in the website or TC must be running in a domain of the Sitecore server. For example, if TC is using the domain "tc.test-server.com", then Sitecore must be using the domain "test-server.com".
  • You must have read/write permissions on the folders in which Sitecore and TC are installed.
  • You must have the ability to upload files to the folder in which Sitecore and TC are installed.
  • You must have an administrator account on Sitecore and TC
If you have all of these things ready, you are safe to proceed. Don't be overwhelmed by the number of steps. It's not as bad as it may look :-)

Step 1 - Download the integration module.
The integration module can be downloaded from the Sitecore's SVN server. The easiest way to get the module is to use an SVN client for Visual Studio like AnkhSVN. You want to download the trunk code since this contains the latest bug fixes.


Step 2 (optional) - Compile the .NET assemblies.
You don't have to recompile the .NET assemblies, but I think it's a good idea because it will ensure that you are using the latest available code. Here's a description of each of the C# projects that make up the integration module so you understand what you are compiling:
  • Sitecore.CommunityServerSecurityIntegration.CommunityServerSide - This assembly is deployed to the TC server. It contains code to support single sign-on as well as extensions to TC's REST API.
  • Sitecore.CommunityServerSecurityIntegration.SitecoreSide - This assembly is deployed to the Sitecore server. It contains code that allows Sitecore to create the cookies that are used by TC and to migrate existing TC users into Sitecore.
  • Sitecore.CommunityServersIntegration.Controls - This assembly is deployed to the Sitecore server. It is where the components that are used to access TC content are defined.
  • CSComponentWizard - This assembly is deployed to the Sitecore server. It is where Sitecore client user interface additions are implemented.

Step 3 - Deploy assemblies to TC.
Copy the assembly "Sitecore.CommunityServerSecurityIntegration.CommunityServerSide.dll" to the TC server. The assembly should go in the bin folder.


Step 4 - Add a security extension in TC.
New functionality can be added to TC using extensions. A security extension allows TC to use cookies that are created by Sitecore for single sign-on.

In order to use an extension, TC must be configured to allow extensions to run. In the "communityserver.config" file in TC, set the following attribute:
  • node path:/CommunityServer/Core/extensionModules
  • attribute name: enabled
  • attribute value: true
Next you need to specify that TC should use a custom class to handle forms authentication. In the extensionModules node you just modified, find the FormsAuthentication security extension. Hint: look for <add name="FormsAuthentication"... Replace the node with the following:

<name="formsauthentication" name="FormsAuthentication" extensiontype="Security" type="Sitecore.CommunityServerSecurityIntegration.CommunityServerSide.SitecoreFormsAuthentication, Sitecore.CommunityServerSecurityIntegration.CommunityServerSide" allowautouserregistration="true" userprofilecookie="CSUserProfile" useencryptedcookie="false" profilerefreshinterval="1" />

Here's a breakdown of what the attributes mean:
  • name - The name of the extension you are configuring.
  • extensionType - TC supports a variety of extensions. This specifies that this extension deals with security.
  • type - The name of the class (and assembly) that implements the extension.
  • allowAutoUserRegistration - When a user logs in from Sitecore, an authentication cookie is created. TC uses that cookie to authenticate the user. If the user doesn't already exist in TC, this setting instructs TC to create the user.
  • userProfileCookie - The name of the cookie that contains user profile information about the user who has been authenticated by Sitecore. TC uses the cookie's value to set values on the TC user. Later you will configure the setting in Sitecore that sets this value.
  • useEncryptedCookie -Specifies if the value saved in the userProfileCookie is encrypted. Later you will configure the setting in Sitecore that sets this value.
  • profileRefreshInterval - This value specifies the frequency with which TC will refresh user information. The unit is in days, with 1 being the minimal value.

Step 5 - Enable REST API in TC.
TC provides access to its content through a REST API. This API must be enabled before Sitecore can use it.
  1. Log into TC using an administrator account.
  2. Navigate to the TC control panel and click the "Site Administration" link.
  3. Click the "Manage REST API" tab.
  4. Make sure the "Yes" option is selected and click the "Save" button.

Step 6 - Generate an application key in TC.
Sitecore uses a TC admin account in order to retrieve content. For this to work, Sitecore needs the TC admin user name and an application key.
  1. Log into TC using the admin account you intend to have Sitecore use.
  2. Edit the user's settings.
  3. Navigate to the "Site Options" tab.
  4. Scroll to the bottom of the screen and click the "Create and Edit Application Keys" link.
  5. In the "name" field enter "Sitecore" and click the "Generate" button.
  6. Write down the API key that is generated. You will need this value when you configure the connection from Sitecore to TC.

Step 7 - Modify web handlers in TC.
This integration module allows Sitecore users to filter and repurpose TC content. In order to provide Sitecore users with a variety of ways to do this, TC's REST API had to be extended.

This step involves changing the web handlers that process the REST calls. These web handlers can be found in the api\ folder under TC. The following files need to be modified. The class name in each file needs to be changed to the value following the file name:
  1. groups.ashx: CommunityServer.WebServices.Services.CSIGroupsService
  2. mediagallery.ashx: CommunityServer.WebServices.Services.CSIMediaGalleriesService
  3. membership.ashx: CommunityServer.WebServices.Services.CSIMembershipService
  4. search.ashx: CommunityServer.WebServices.Services.CSISearchService

Step 8 - Install the integration module deployment package in Sitecore.
The deployment package is available in the file named "TCSC Integration - Sitecore side-1.1.x.zip". Install this package using the Sitecore Installation Wizard.

The package includes a number of Sitecore items and files that are copied to the filesystem. Some of those files are .NET assemblies. If you recompiled the assemblies earlier, you will want to copy those assemblies into the bin\ folder in Sitecore.


Step 9 - Add a connection string in Sitecore.
Since TC is an external system that Sitecore is connecting to, an entry for TC must be added to Sitecore's connectionstring.config file. Add the following to the configuration file:

<add name="tc" connectionstring="siteUrl=http://your-server.com/tc;username=admin;apiKey=c00y45fd" />

Of course, the specific values you enter here will be different than the ones above. Here's an explanation of the values in the connectionString attribute:
  • siteUrl - The base URL to your TC server. If you enter the URL in a browser you should be taken to the TC homepage.
  • username - The name of the TC administrator account that Sitecore uses to communicate with TC. This must be the same account you used earlier to generate the API key.
  • apiKey - The API key value you generated earlier.

Step 10 - Modify the integration module configuration file in Sitecore.
One of the files that is created by the deployment package is the integration module configuration file. This file is located in the folder "app_config/include/". The name of the file is "CommunityServerIntegration.config".

Locate the node "/configuration/sitecore/settings". This node defines the basic settings used by the integration module. Here's a description of the settings:
  • CS.ProfileCookie - Remember the "userProfileCookie" attribute in TC's "communityserver.config" file? This value must match that.
  • CS.EncryptProfile - This value must match the "useEncryptedCookie" attribute value from TC's "communityserver.config" file.
  • CS.ConnectionStringName - This value must match the name of the connection string you configured in Sitecore's "connectionstring.config" file.
Using the values I've already configured, this is what my settings node looks like:

<settings>
<setting name="CS.ProfileCookie" value="CSUserProfile" />
<setting name="CS.EncryptProfile" value="false" />
<setting name="CS.ConnectionStringName" value="tc" />
</settings>



Step 11 - Configure forms authentication settings in Sitecore.
In order for single sign-on to work, both Sitecore and TC must use forms authentication. Additionally, the forms authentication settings for both must match. Make sure the "authentication" node in Sitecore's "web.config" file matches the node in TC's "web.config" file.

The important part here is the the authentication form's name and domain match. Here's the authentication node from my installation:

<authentication mode="Forms">
<forms name=".CommunityServer" protection="All" timeout="60000" loginurl="login.aspx" slidingexpiration="true" domain=".nicam.com" />
</authentication>

The domain attribute is required if TC is running in a subdomain. The dot before the domain name is needed in order for the browser to use the same cookie when sending requests to either the domain or the subdomain.

Also - and this may be common knowledge among developers but it can't hurt to be repeated - be sure your domain has at least one dot in it already. The cookie will not be written if your domain is simply "nicam". It needs to be "nicam.com".


Step 12 - Ensure the machineKey values in Sitecore and TC match.
The "machineKey" settings is important when using forms authentication in ASP.NET. Both Sitecore and TC must have the same "machineKey" configuration.

This configuration can be found in web.config. If no "machineKey" configuration exists, it must be added. Online tools are available - like this one - to generate the required settings. After you generate the configuration, add it to web.config as the last tag before the closing "system.web" tag (</system.web>).


Step 13 (optional) - Configure role and property mappings from Sitecore to TC.
Sitecore's "CommunityServerIntegration.config" file contains 2 sections that allow Sitecore user settings to be mapped to TC user settings.

The first mapping section is "rolesCorrespondence". This section allows you to specify user roles in Sitecore but still take advantage of security in TC. Sitecore roles are mapped to TC roles.

When the authentication cookie is created, the Sitecore user's roles are checked against this setting. The names of the appropriate TC roles are set in the authentication cookie. When single sign-on happens in TC, the custom forms authentication class that TC uses reads the roles from the authentication cookie and adds those roles to the TC user.

The following is an example of role mapping:

<rolesCorrespondence>
<role communityserverrole="Employees" sitecorerole="sitecore\Author" />
<role communityserverrole="Visitors" sitecorerole="extranet\Nicam" />
</rolesCorrespondence>


The second mapping section is "mappedProfileProperties". This is where Sitecore user profile properties are mapped to TC user profile properties. These values are passed to TC through the user profile cookie.

<mappedProfileProperties>
<property communityserverproperty="PublicEmail" sitecoreproperty="Email">
<property communityserverproperty="CommonName" sitecoreproperty="FullName">
</mappedProfileProperties>



Step 14 - Enable the HTML editor for display templates
Display templates determine how content retrieved from TC by the community component is formatted. Sitecore users are able control this presentation by using a rich text editor to edit display templates.

A couple of changes to the Sitecore file "/sitecore/shell/Controls/Rich Text Editor/Default.aspx" are required:
  1. Change the "Inherits" attribute to "Sitecore.CommunityServerIntegration.Editors.CSRADEditor". This class extends the standard Sitecore rich text editor to support the dropdown list that allows an editor to select the specific TC content fields to display.
  2. At the bottom of the file, add a link to the Javascript file "/sitecore modules/Shell/CSSCIntegration/RichText Commands.js". It is important that this be the last Javascript file that the browser loads. Otherwise the code in the file may be overriden by another script.

Next steps
The integration module is installed, but there's more work to do. Since Sitecore is handling authentication and is responsible for role management, existing TC users must be migrated into Sitecore. Also, Sitecore needs to be configured to create the cookies (authentication and user profile) that TC needs in order to sign a user in. I will cover these topics in my next post.

Want to learn more?

14 comments:

  1. So if an end user creates an account thru the site, on the backend that user would need to be created in the Sitecore CMS only. There is not syncing back to TC.

    If I wanted a feature of validating the user is the owner of the email account by sending an email, I would need to build a custom process for that. I can't take advantage of the built in feature of TC. Correct?

    ReplyDelete
  2. Yes, the account would be created on the Sitecore side. When the new Sitecore user navigates to TC for the first time, a new TC account will be created automatically.

    And, yes. If you want to use TC's email verification features you would need to build a custom process.

    ReplyDelete
  3. What if I don't want to integrate sitecore security with telligent and avoid using forms authentication? How would the I integrate them?

    ReplyDelete
  4. Thank you for writing these instructions they are appreciated as the docs that come with the module are not much help. After going through and completing the configuration and not getting any errors from the wizard. I am left with a "Can't render community content." in the layout where the forum should be. None of my logs show an error or a connection issue, any idea where I might start to look for a problem? This is a clean new installation and I have set up and posted with users and forums on the telligent side so there is something to find. Any help would be appreciated.
    Regards

    ReplyDelete
  5. The "Can't render community content" message is very generic. It is displayed when an exception is thrown by the renderCSContent pipeline. More detailed error messages should be available in the log file, but you write that you don't see anything in the log file.

    Are you trying to view the content in the page editor or page preview mode, or in a published site?

    Are you using the admin account? I've encountered some cookie-related problems at times (the session cookie not being properly removed). I'm always careful to use a separate browser for testing the integration, and never to be logged into Sitecore as admin and then try to view Telligent content.

    Another option is to download the source code and start up the debugger. That's actually not as bad as it sounds, and it should reveal the problem very quickly.

    ReplyDelete
  6. Thank you for the quick reply, I went back to the logs and it is a parser error.

    Exception information:
    Exception type: HttpParseException
    Exception message: The page must have a <%@ webhandler class="MyNamespace.MyClass" ... %> directive.

    I will be going through the source code and adding a clearer error message this week.

    It was not rendering in either the preview or published mode, which browser or platform didn't seem to have an effect. I found out the hard way about using different browsers for admin and viewing work, thanks though.

    Will keep you posted on the progress, thank you again.

    ReplyDelete
  7. I have the full error message from the log...
    + System

    - Provider

    [ Name] ASP.NET 2.0.50727.0

    - EventID 1310

    [ Qualifiers] 32768

    Level 3

    Task 3

    Keywords 0x80000000000000

    - TimeCreated

    [ SystemTime] 2011-01-31T16:39:17.000Z

    EventRecordID 4904

    Channel Application

    Computer

    Security


    - EventData

    3006
    A parser error has occurred.
    1/31/2011 11:39:17 AM
    1/31/2011 4:39:17 PM
    47b77146cc354a288ced149a66343505
    3
    1
    0
    /LM/W3SVC/2/ROOT-1-129409655532421195
    Full
    /
    C:\inetpub\Telligent_Community\


    2500
    w3wp.exe
    NT AUTHORITY\NETWORK SERVICE
    HttpParseException
    The page must have a <%@ webhandler class="MyNamespace.MyClass" ... %> directive.
    http:///api/forums.ashx/forumgroups/3
    /api/forums.ashx/forumgroups/3


    False

    NT AUTHORITY\NETWORK SERVICE
    3
    NT AUTHORITY\NETWORK SERVICE
    False
    at System.Web.UI.SimpleWebHandlerParser.ParseReader() at System.Web.UI.SimpleWebHandlerParser.Parse(ICollection referencedAssemblies) at System.Web.Compilation.SimpleHandlerBuildProvider.get_CodeCompilerType() at System.Web.Compilation.BuildProvider.GetCompilerTypeFromBuildProvider(BuildProvider buildProvider) at System.Web.Compilation.BuildProvidersCompiler.ProcessBuildProviders() at System.Web.Compilation.BuildProvidersCompiler.PerformBuild() at System.Web.Compilation.BuildManager.CompileWebFile(VirtualPath virtualPath) at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile) at System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile) at System.Web.Compilation.BuildManager.GetVPathBuildResult(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile) at System.Web.UI.SimpleHandlerFactory.System.Web.IHttpHandlerFactory2.GetHandler(HttpContext context, String requestType, VirtualPath virtualPath, String physicalPath) at System.Web.HttpApplication.MapHttpHandler(HttpContext context, String requestType, VirtualPath path, String pathTranslated, Boolean useAppConfig) at System.Web.HttpApplication.MapHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

    Not really sure how to fix this.

    ReplyDelete
  8. I am still unable to find and answer for the errors I am getting, I have contacted Sitecore and Telligent(who said they do not support third party modules instead of answering a simple question). I posted the other day and Pat at Sitecore recommended I contact you again. Here is what is going on:

    This is the string that is returned from the CSComponent.cs DoRender class
    Application=Forum&MethodName=GetGroupForums&GroupIDs=3&FilterByUser=False&HeaderTemplate={671CF90C-D51E-471B-BA2D-E1C472BE6801}&ItemTemplate={66CBB603-200C-4447-8B6D-FBB3ABFBDF03}&AlternateItemTemplate={403AB787-30A4-4464-9172-4E471093CBAB}&Enabled=True

    This is the error from IIS:
    + System
    - Provider
    [ Name] ASP.NET 2.0.50727.0
    - EventID 1310
    [ Qualifiers] 32768
    Level 3
    Task 3
    Keywords 0x80000000000000
    - TimeCreated
    [ SystemTime] 2011-01-31T16:39:17.000Z
    EventRecordID 4904
    Channel Application
    Computer
    Security
    - EventData
    3006
    A parser error has occurred.
    1/31/2011 11:39:17 AM
    1/31/2011 4:39:17 PM
    47b77146cc354a288ced149a66343505
    3
    1
    0
    /LM/W3SVC/2/ROOT-1-129409655532421195
    Full
    /
    C:\inetpub\Telligent_Community\
    2500
    w3wp.exe
    NT AUTHORITY\NETWORK SERVICE
    HttpParseException
    The page must have a <%@ webhandler class="MyNamespace.MyClass" ... %> directive.
    http:///api/forums.ashx/forumgroups/3
    /api/forums.ashx/forumgroups/3

    False
    NT AUTHORITY\NETWORK SERVICE
    3
    NT AUTHORITY\NETWORK SERVICE
    False
    at System.Web.UI.SimpleWebHandlerParser.ParseReader() at System.Web.UI.SimpleWebHandlerParser.Parse(ICollection referencedAssemblies) at System.Web.Compilation.SimpleHandlerBuildProvider.get_CodeCompilerType() at System.Web.Compilation.BuildProvider.GetCompilerTypeFromBuildProvider(BuildProvider buildProvider) at System.Web.Compilation.BuildProvidersCompiler.ProcessBuildProviders() at System.Web.Compilation.BuildProvidersCompiler.PerformBuild() at System.Web.Compilation.BuildManager.CompileWebFile(VirtualPath virtualPath) at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile) at System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile) at System.Web.Compilation.BuildManager.GetVPathBuildResult(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile) at System.Web.UI.SimpleHandlerFactory.System.Web.IHttpHandlerFactory2.GetHandler(HttpContext context, String requestType, VirtualPath virtualPath, String physicalPath) at System.Web.HttpApplication.MapHttpHandler(HttpContext context, String requestType, VirtualPath path, String pathTranslated, Boolean useAppConfig) at System.Web.HttpApplication.MapHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)


    As I said previously we are(were) on a tight deadline. Any direction would be appreciated.

    ReplyDelete
  9. I fixed the error, thanks.

    ReplyDelete
  10. We are not having much luck with this supposedly easy installation. I have the connection from sitecore working, the forums module displays in the sitecore placeholder. The current issue is the single sign on not carrying over from the sitecore login to the telligent as displayed in your earlier video blogs. It does how ever carry back the other way, if I log into telligent it does log back into sitecore. The cookie .CommunityServer gets destroyed when I try and open a telligent tab in the same browser window. I am using the sitecore virtual user as we are storing the user credentials in a different system. Telligent does not seem to be creating authenticated users. Why would telligent over write the existing cookie.

    Any Idea's?

    ReplyDelete
  11. I never claimed the installation was easy :-) There are a lot of variables involved.

    First of all, I recommend posting this sort of question to SDN. Much more traffic goes through that site than this old blog.

    When you write that the cookie gets destroyed, have you confirmed that Sitecore is creating the cookie? If that is happening, then it sounds like the best course of action is to connect a debugger to the Telligent side. Then look at the class Sitecore.CommunityServerSecurityIntegration.CommunityServerSide.SitecoreFormsAuthentication, because it is responsible for handling the cookie in Telligent. Stepping through that code should reveal the problem... or at least get you pointed in the right direction.

    ReplyDelete
  12. Your blog seems to be the only place we can actually get a reply on our questions, it is appreciated. Yeah I did the debugging and nothing popped up, Sitecore is definitely writing the cookie. When I open a new tab and go to the telligent site on the same server in a subdomain it redirects to the login page and the cookie disappears but a new one differently named appears, which effectively logs the user out of sitecore. When I then log into telligent it creates the .CommunityServer cookie and then refresh the sitecore page the login is functional again.

    We are also getting an intermittent error:
    "Could not resolve type name: Security.CSAuthenitcationProvider,..." To fix it I end up commenting out the authentication section in the ComunityServerIntegration.config file and restarting the IIS and application pool. This one is kind of baffling because it will pop up after working just fine for several hours.
    Thanks

    ReplyDelete
  13. Double check that you followed step 11. I was just able to replicate your problem on my end by omitting that step.

    In my case, sitecore is running on nicam.com and Telligent on tc.nicam.com. If if I log into nicam.com and then try to navigate to tc.nicam.com, the nicam.com cookie is not recognized. But if I log into tc.nicam.com and then try to navigate to nicam.com, the cookie is recognized.

    Step 11 is required in order for the cookie written by nicam.com to be recognized by tc.nicam.com.

    ReplyDelete
  14. Thanks again,
    That node is identical in the sitecore and telligent web.config. I have also tried integrating the SecurityUtil.AfterLogin(user.Name, true) as recommended in the Docs but that still doesn't correct the issue.

    Could it be in the FormsAuthentication node in the communityserver.config file? That is configured according to the Docs, or in the CustomAuthentication node(which I have commented in and out with no visible effect).

    I posted to the SDN forums as you suggested, maybe someone will come up with an answer.

    ReplyDelete

Note: Only a member of this blog may post a comment.