Article Default REST Host

The Default REST Host is the most robust of the hosts shipped in the SDK.  This host not only allows access to REST it handles OAuth authentication, local user resolution, user synchronization and Single Sign On.  This host type can only be used in web projects.

Lifecycle

Default REST Hosts are self initializing meaning that they load themselves from the configuration data you provide the first time they are requested.   From that point on the host remains in memory for the entire duration of the application process.  You force create a host and retrieve that host from memory using a static GET method on the host itself and providing the name:

var restHost = Telligent.Evolution.Extensibility.Rest.Version1.Host.Get("default");

Setup

You will need to create an Oauth client in your community that is private and has the Authorization Code with Trusted Client checked and Client Credentials grant types.   For the callback Url it is the path to the Oauth.ashx file in your application which by default is the root(this file was installed by the SDK).  An example would be http://mySDkSite.com/oauth.ashx where mySDKSite.com is the main url of the third party site, not your community.

The Default REST Host is driven by configuration in the communityserver_SDK.config file.   This contains a single entry for a host named "default".  You can change this if you so desire but make note of the new name as it is used later to load the host.  In all examples we will use default.

Here is an example of the configuration:

<communityServerHosts>
  <host name="default" communityServerUrl="http://yourcommunitysite.com/">
    <oauth clientId="[Oauth Client Id]" 
           clientSecret="[OAuth Secret]" 
           callbackUrl="~/oauth.ashx" 
           cookieName="evoUser"
           defaultLanguage="en-US"
           anonymousUsername="Anonymous">
      <localAuthentication enabled ="true" membershipAdministrationUsername="admin" />
      <sso enabled="true" synchronizationCookieName="EvolutionSync" />
    </oauth>
   <remoteProxy enabled="false" callbackUrl="~/proxy.ashx" />
  </host>
</communityServerHosts>

Host node

<host name="default" communityServerUrl="http://yourcommunitysite.com/">

This is the main node to define a host, all other configuration options are child elements of this node.   This node aside from containing other configuration options also identifies 2 pieces of information:

  • name:  The name that identifies this host and will be used to reference this host in code.  If there are multiple hosts names must be unique.
  • communityServerUrl: The fully qualified domain name of your community site

OAuth Node

This is another required node as it identifies how to authenticate with your community. It is a direct descendent of the host node. It uses a combination of authorization code based authentication with OAuth and client credentials.

<host name="default" communityServerUrl="http://yourcommunitysite.com/">
    <oauth clientId="[Oauth Client Id]" 
           clientSecret="[OAuth Secret]" 
           callbackUrl="~/oauth.ashx" 
           cookieName="evoUser"
           defaultLanguage="en-US"
           anonymousUsername="Anonymous">
    </oauth>
   <remoteProxy enabled="false" callbackUrl="~/proxy.ashx" />
  </host>

In addition to child configuration objects the Oauth node requires the following information:

  • clientId: The Oauth client ID you setup earlier
  • clientSecret: The Oauth client secret you setup earlier
  • callbackUrl: The relative, application escaped path to the oauth.ashx installed with the SDK.  By default it is at the root (~/oauth.ashx) but can be moved provided its defined appropriately in this value AND is correct in your Oauth configuration in your community.
  • cookieName:  This is the name of the cookie the SDK writes to track the user.  This keeps the SDK from making continuous calls to authenticate a user.
  • defaultLanguage:  At this time this attribute is not functional and deprecated.  It will be removed in a future release.
  • anonymousUsername:  This is the account used when a user is not considered authenticated.  It must be an existing user account and is recommended to use the default Anonymous account.

Using Evolution Users for Authentication

The default behavior is to initiate the OAuth flow and allow users to sign into their community accounts in the community and then your site is furnished a token that the SDK uses.  In this process however you need to create a login link  for the user to use.  You can do that using this host specific method:

 

var restHost = Host.Get("default");
var loginUrl = restHost.CommunityOAuthLoginUrl(returnUrl);

Logging out is slightly different.  Here you need to create a method that fires either through postback or redirect to a page that executes the following code:

var restHost = Host.Get("default");
restHost.CommunityOAuthLogout();

Using your Existing User Accounts

<oauth clientId="[Oauth Client Id]" 
           clientSecret="[OAuth Secret]" 
           callbackUrl="~/oauth.ashx" 
           cookieName="evoUser"
           defaultLanguage="en-US"
           anonymousUsername="Anonymous">
           
      <localAuthentication enabled ="true" membershipAdministrationUsername="admin" />
      
    </oauth>

If you want to use the user base you already have defined you can  by adding the localAuthentication node under the oauth node, enabling it and configuring it with the following parameters:

  • enabled: Turns the node on or off without needing to remove it
  • membershipAdministrationUsername: A user with permission enough to manage users in your community. 

You will also need to wire up the host object to identify users in your system.  You must provide at least a username and email address and the MUST BE UNIQUE in the community.  If you allow duplicate usernames or emails you will need to address this in some fashion as the community will not allow this.   The way it works is the SDK will ask your application who is logged in.  Using the information you provide the user will locate an account or automatically create one.  The way the SDK asks for this information is through the ResolveLocalUser Function of the host.  You should define this when your application starts.

var restHost = Telligent.Evolution.Extensibility.Rest.Version1.Host.Get("default");
restHost.ResolveLocalUser = (host, resolveArgs) =>
{
    //This where you identify your logged in user
    return new Telligent.Evolution.Extensibility.Rest.Version1.LocalUser("jdoe", "jdoe@somedomain.com");
};

Single Sign-On

*To use single sign on your site and community must share a domain.

If you want to use SSO, first log in to your community control panel or administration area depending on version.  For 9.0 and later locate User Synchronization Cookie under the integration menu.  For earlier versions you will find User Synchronization under Membership Administration->Configuration->Cookie Settings.

1. Enable the User Synchronization cookie.

2. Set the domain of your site and community. If you have one site on local.com but community at community.local.com, set this to  .local.com.

3. Change the cookie name if desired.  Record this value for use later.

4. Click Save.

To use single sign on on your site add the sso node as a direct descendent of the oauth node in the communityserver_SDK.config file.

 <oauth clientId="[Oauth Client Id]" 
           clientSecret="[OAuth Secret]" 
           callbackUrl="~/oauth.ashx" 
           cookieName="evoUser"
           defaultLanguage="en-US"
           anonymousUsername="Anonymous">
      <localAuthentication enabled ="true" membershipAdministrationUsername="admin" />
      <sso enabled="true" synchronizationCookieName="EvolutionSync" />
</oauth>

Adjust the properties on this node:

  • enabled: Turn this feature on or off
  • synchronizationCookieName: This value must match the cookie name you defined for User Synchronization above.

Once you have this working you will probably need to make adjustments to community.  Since this is not a traditional SSO module you will need to adjust the login and logout links in community by editing the widgets.  They will now need to point to your custom login or logout screens.

How it works

The first time you make a REST call from a host it will silently invoke the SSO process.  It does this by signing a redirect url with user information and sending it over to community, community then validates the information and logs the user in.  It writes the synchronization cookie so the community remembers who was logged in when a user is redirected to the community.

If you want to force the process when you first login and not wait for the first usage you can do so.  You would inject code into your authentication code.  The most appropriate place is right before you redirect a user after authenticating them.

 //This would be whatever returnUrl you would redirect to after authentication
string returnUrl = "http://locahost"; 

//Your authentication code for your site

//before redirecting
var restHost = Host.Get("default");
var newReturnUrl = restHost.ProcessSynchronizedLogin(returnUrl);
HttpContext.Current.Response.Redirect(newReturnUrl);

This takes your return url, adds it to a signed community Url, and then you redirect to the new community Url that forces the login.  Once done community will redirect you to your original return url.

Logging out is an identical process, but in your log out code you would use:

//This would be whatever returnUrl you would redirect to after authentication
string returnUrl = "http://locahost"; 

//Your logout code for your site

//before redirecting
var restHost = Host.Get("default");
var newReturnUrl = restHost.ProcessSynchronizedLogout(returnUrl);
HttpContext.Current.Response.Redirect(newReturnUrl);

 Url Proxying

All REST Urls will return you fully qualified urls to your community. If by some chance you don't want to redirect to community you can tell the SDK to return a proxy instead.  This means where you used to get the community url, you will now receive a url to a local http handler.  That handler will invoke a host process where you can make decisions about what url to return.

Add a new ASHX file to your site and set the source to

<%@ WebHandler Language="C#" Class="Telligent.Evolution.Extensibility.Rest.Version1.UrlProxy, Telligent.Rest.SDK"  %>

You can also use that same class to register the handler as a route or other method.

As a child of the host node add the remote proxy node shown here:

 

<host name="default" communityServerUrl="http://yourcommunitysite.com/">
    <oauth clientId="[Oauth Client Id]" 
           clientSecret="[OAuth Secret]" 
           callbackUrl="~/oauth.ashx" 
           cookieName="evoUser"
           defaultLanguage="en-US"
           anonymousUsername="Anonymous">
      <localAuthentication enabled ="true" membershipAdministrationUsername="admin" />
      <sso enabled="true" synchronizationCookieName="EvolutionSync" />
    </oauth>
   <remoteProxy enabled="true" callbackUrl="~/proxy.ashx" />
  </host>

Set the properties:

  • enabled: Turn this feature on or off
  • callbackUrl:  The relative application escaped url of the handler you just created.

 

When your application starts you will need to add the function that handles the urls:

var restHost = Host.Get("default");
restHost.GetRedirectUrl = (host, url, urlArgs) =>
{
   //The url parameter is the you can use it to evaluate if you need to redirect it.
   //Return the Url you wish to redirect to
   return url;
};

You will get an instance of the host making the call, the community url being requested, and an arguments object that currently gives you access to the current HttpContext.

Evaluate the incoming Url to meet your needs and if you wish to send it to another Url, return the new destination url.  If you conclude you do not wish to send it to a different url, simply return the url sent in as is.  If you wanted to parse context specific information from a community url can can make a REST call from your function to the remote entity endpointgiving it the incoming url.

Multiple Hosts

It is possible to have multiple hosts if needed.  And example of when this might be appropriate is if you have multiple communities you want to talk to from a single application, or your application supports multiple sites and each site is mapped to a host.

Another host is simply another host node in configuration:

<communityServerHosts>
  <host name="default" communityServerUrl="http://yourcommunitysite.com/">
    <oauth clientId="[Oauth Client Id]" 
           clientSecret="[OAuth Secret]" 
           callbackUrl="~/oauth.ashx" 
           cookieName="evoUser"
           defaultLanguage="en-US"
           anonymousUsername="Anonymous">
      <localAuthentication enabled ="true" membershipAdministrationUsername="admin" />
      <sso enabled="true" synchronizationCookieName="EvolutionSync" />
    </oauth>
   <remoteProxy enabled="false" callbackUrl="~/proxy.ashx" />
  </host>
  <host name="SiteB" communityServerUrl="http://AnotherCommunitySite.com/">
    <oauth clientId="[Oauth Client Id]" 
           clientSecret="[OAuth Secret]" 
           callbackUrl="~/oauth.ashx" 
           cookieName="SiteUser"
           defaultLanguage="en-US"
           anonymousUsername="Anonymous">
      <localAuthentication enabled ="true" membershipAdministrationUsername="admin" />
      <sso enabled="true" synchronizationCookieName="EvolutionSync" />
    </oauth>
   <remoteProxy enabled="false" callbackUrl="~/proxy.ashx" />
  </host>
</communityServerHosts>

You need to make sure it is a different host name.  Also you might consider using different cookie names to avoid conflicts.  You do not need to duplicate the oauth.ashx or proxy.ashx as they understand host instances.

Then you get you new host by its name:

 var restHost = Host.Get("SiteB");