The number of social networking platforms has been growing at a steady rate over the last couple of years. Diversity is a good thing, but it would be even better if you wouldn't need to keep up with a growing list of site-specific APIs. To overcome this problem, the
OpenSocial group was formed in 2007 to define a common API for social applications across multiple websites. The good news is that the upcoming release of MonoX includes the support for the
OpenSocial Server API 1.1. To the best of our knowledge, it is the first downloadable ASP.NET CMS application with such level of support for the OpenSocial standard.
First we'll give a brief technical overview of the OpenSocial server implementation and later we'll take a look on how it is implemented in MonoX.
OpenSocial server is standalone library that handles oAuth authentication plus REST and OpenSocial protocol details. To enable OpenSocial server you need to add the server configuration section in the web.config:
<
configSections
>
<
section
name
=
"openSocial"
type
=
"OpenSocial.Configuration.OpenSocialConfiguration, OpenSocial"
requirePermission
=
"false"
/>
</
configSections
>
After that we can continue by specifying MonoX-specific implementation details:
<
openSocial
tokenManager
=
"MonoSoftware.MonoX.BusinessLayer.OAuthTokenManagerBLL, MonoX"
authorizationEndpoint
=
"/MonoX/OpenSocial/OAuth.ashx"
authenticationPage
=
"/MonoX/OpenSocial/OpenSocialAuthorizationPage.aspx"
dataAccessAdapter
=
"MonoSoftware.MonoX.OpenSocial.MonoXOpenSocialDataAccessAdpater, MonoX"
/>
All configuration attributes displayed above are required.
tokenManager points to the class that implements the
oAuth token manager that subsequently requires implementation of the two interfaces:
DotNetOpenAuth.OAuth.ChannelElements.ITokenManager and
DotNetOpenAuth.OAuth.ChannelElements.IServiceProviderTokenManager. Both interfaces are a part of the
dotnetOpenAuth thrid party library used for handling oAuth protocol details.
dataAccessAdapter is pointing to the implementation of the OpenSocial services data access methods that require implementation of the
OpenSocial.Service.IOpenSocialDataAccessAdapter interface.
authorizationEndpoint is defining the physical path to the oAuth handler used to negotiate and authenticate oAuth requests.
authenticationPage specifies the authorization page where users can decide if they will allow access to their resources or not. This is the point where token will be authorized. To fully implement the authentication page you have to posses some basic knowledge about the
oAuth protocol and the dotnetOpenAuth library. Since oAuth protocol allows flexible and temporal permissions, specific authorization implementation details can vary. MonoX sample implementation gives access to all resources for unlimited time. At this moment, OpenSocial server supports only 3-legged oAuth, you can find more about oAuth use for the OpenSocial REST API in this
paper.
Below is the code for our sample authentication page:
Front end:
<%@ Page Title=""
Language="C#"
MasterPageFile="/MonoX/MasterPages/Default.master"
AutoEventWireup="true"
CodeBehind="OpenSocialAuthorizationPage.aspx.cs"
Inherits="MonoSoftware.MonoX.OpenSocial.OpenSocialAuthorizationPage" %>
<
asp:Content
ID
=
"Content1"
ContentPlaceHolderID
=
"cp"
runat
=
"server"
>
<%= String.Format
(MonoSoftware.MonoX.Resources.DefaultResources.OpenSocial_RequestMessage,
CurrentToken.OaConsumer.Name) %>
<
asp:Button
ID
=
"btnAllow"
runat
=
"server"
Text
=
"Allow"
/>
<
asp:Button
ID
=
"btnDeny"
runat
=
"server"
Text
=
"Deny"
/>
</
asp:Content
>
Code behind:
using
System;
using
System.Security;
using
DotNetOpenAuth.OAuth.Messages;
using
MonoSoftware.MonoX.DAL.EntityClasses;
using
OpenSocial.Service;
namespace
MonoSoftware.MonoX.OpenSocial
{
public
partial
class
OpenSocialAuthorizationPage : BasePage
{
#region Properties
private
OaTokenEntity _currentToken =
null
;
protected
OaTokenEntity CurrentToken
{
get
{
if
(_currentToken ==
null
)
{
ITokenContainingMessage requestTokenMessage = OpenSocialOAuthServiceProvider.PendingAuthorizationRequest;
_currentToken =
(OaTokenEntity)
OpenSocialOAuthServiceProvider.ServiceProvider.TokenManager.GetRequestToken
(requestTokenMessage.Token);
}
return
_currentToken;
}
}
#endregion
#region Page Events
protected
void
Page_Init(
object
sender, EventArgs e)
{
if
(!Page.User.Identity.IsAuthenticated)
{
throw
new
SecurityException();
}
btnAllow.Text = MonoSoftware.MonoX.Resources.DefaultResources.OpenSocial_Allow;
btnDeny.Text = MonoSoftware.MonoX.Resources.DefaultResources.OpenSocial_Deny;
btnAllow.Click +=
new
EventHandler(btnAllow_Click);
btnDeny.Click +=
new
EventHandler(btnDeny_Click);
}
protected
void
Page_Load(
object
sender, EventArgs e)
{
}
#endregion
#region UI Events
protected
virtual
void
btnDeny_Click(
object
sender, EventArgs e)
{
OpenSocialOAuthServiceProvider.PendingAuthorizationRequest =
null
;
}
protected
virtual
void
btnAllow_Click(
object
sender, EventArgs e)
{
// Use OpenSocialOAuthServiceProvider for handling OAuth tokens
var tokenManager = OpenSocialOAuthServiceProvider.ServiceProvider.TokenManager;
// Pending authorization request is passed through session
var pendingRequest = OpenSocialOAuthServiceProvider.PendingAuthorizationRequest;
var requestToken = CurrentToken;
requestToken.UserId = MonoSoftware.MonoX.Utilities.SecurityUtility.GetUserId();
// You can set token expiration date using requestToken.ExpirationDate
// e.g. requestToken.ExpirationDate = DateTime.UtcNow.AddHours(3);
// Use requestToken.Scope for a scope of permissions requested
tokenManager.UpdateToken(requestToken);
var response = OpenSocialOAuthServiceProvider.AuthorizePendingRequestTokenAsWebResponse();
if
(response !=
null
)
{
// The consumer provided a callback URL that can take care of everything else.
response.Send();
}
}
#endregion
}
}
OpenSocialOAuthServiceProvider is a static class inside OpenSocial server library that provides methods for handling OAuth authorization tasks. When a service recevie user authorization request token it will store this request in a session and transfer execution to the authentication page. Using this token we can access OaTokenEntity, a MonoX object representing OAuth token, and set all required parameters before authorizing it. In this case we expect consumer to provide a callback URL in its request parameters; a scenario where callback url is known to the server in advance is not currently covered in MonoX.
Now that we have covered the OpenSocial server configuration we can proceed to the server implementation. OpenSocial server is implemented using WCF and requires .net framework 3.5 to run. Currently it implements three OpenSocial services - people, groups and activites - and supports JSON and XML output formats, while JSON is the only supported input format at this moment.
The OpenSocial server is running inside the same process as MonoX CMS. This allows for the easy creation of the authentication page as we can use all the goodies MonoX offers. On the other hand, all service requests are pushed through asp .net request lifecycle and this can affect the behavior of the service. We have experienced several problems when Forms authentication is activated. One of the features of the FormsAuthentication module is that it will redirect all responses with 401-unauthorized status to the login page. As a result, the client will see 301-moved status instead of 401-unauthorized. To avoid this we had to add another module that disables FormsAuthentication module when service request is processed. In order for OpenSocial server to work correctly with Forms authentication, you have to add the OpenSocialModule in your cofiguration:
<
httpModules
>
<
add
name
=
"OpenSocialModule"
type
=
"MonoSoftware.MonoX.OpenSocial.OpenSocialHttpModule, MonoX"
/>
</
httpModules
>
This setting will disable FormsAuthentication module for a default location. Subsequently, it is not possible to move the OpenSocial server to a different location without changing the the module. The server will work correctly with default MonoX settings, but you should be careful if you're adding new modules to the pipeline and you want to use the OpenSocial server.
The default location of the OpenSocial server is "/MonoX/OpenSocial/OpenSocial.svc". To test if the server component is running, you can type this address in your browser (for example,
http://yourdomain/MonoX/OpenSocial/OpenSocial.svc) and you should get the XRDS discovery response with list of supported services and their endpoints:
<
Type
>xri://$xrds*simple</
Type
>
<
Service
>
</
Service
>
<
Service
>
</
Service
>
<
Service
>
</
Service
>
</
XRD
>
</
XRDS
>
If you get a similar response your OpenSocial server is up and running. By default, all resources are protected and you have to authenticate to access them through OpenSocial server. To setup client oAuth provider set all endpoints - authorizeUrl, accessTokenUrl and requestTokenUrl - to OAuth.ashx handler (its default address is http://yourdomain/MonoX/OpenSocial/OAuth.ashx). OpenSocial server is currently in a test phase and at the moment you can't register applications with MonoX. You will need to use a test consumer to authenticate with OpenSocial server - use "Ud4IhqeyIEmEHEmApOWN-A" as the applicationKey and "anonymous" as the secret value. You can find all consumer details in the OaConsumer table inside MonoX database. Application key is constructed from the consumer id as its ShortGuid string representation, while secret is a column in the DB table and can be of any value.