Saturday, January 17, 2009

OAM (Oracle Access Manager) and SharePoint Integration using custom HTTPModule

OAM's integration guide has step by step instructions on OAM and SharePoint integration. However, it works only if Active Directory is the User base for your SharePoint. If your OAM is having LDAP user base you are out of luck for a quick integration. Considering the LDAP as OAM backend and Active Directory as SharePoint user base, the integration still can be done by user data reconciliation from LDAP to Active Directory before the integration and a real time provisioning mechanism afterwards.

What if your organization decided to have SharePoint with LDAP instead of Active Directory? (Our organization has set up SharePoint server for external users (non - employee) who are not in our Active Directory. All our externals users are already available in Sun LDAP). In this unusual scenario, OAM cannot be integrated as it is. Here is how we did it.



Overview of the Integration
(1) User access the SharePoint URL.
(2) OAM's webgate (IIS plug-in/ ISAPI filter developed by Oracle responsible for checking Access policy and authentication etc) intercepts the URL and display our generic login page to user. User put his credentials. OAM webgate then validate it and allow the user to access SharePoint URL. It also set the SSO token in the browser so user can have single sign on with other applications.
(3) At this point SharePoint does not know about the authenticated user even our SharePoint already has LDAPmembership to the same LDAP that used by OAM.
(4) Now the HTTPModule will come to the rescue. It will

a. read the USER_ID from header (set by OAM after the authentication) and
b. create a GenericPrincipal for SharePoint.

fig1.JPG

The outcome of this model is,

(1) Share point will not display its login page to the user.

(2) The user -to-role assignment can still be possible inside SharePoint as SharePoint is also connected to the same LDAP that is used by OAM for authentication (which is also the user db for OAM) through LDAP-membership.
1. Writing an Http Module
My assumption is reader is familiar with OAM set up and knows how to set up a Webgate for IIS server that hosts SharePoint. LDAP set up. My other blog already detailed out on how to set up SharePoint with LDAP as user base. I will focus more on the point 4 mentioned in the overview section which require writing an HttpModule for SharePoint.
The HttpModule does the followings:-

1. Reads the USER_ID from header (set by OAM after the authentication). This header variable (say HTTP_OBLIX_UID) is set by OAM after successful authentication and authorization. This can be defined in 'authorization success event' in the SharePoint URL policy inside OAM.

2. Create a GenericPrincipal for SharePoint.
Step 1: Write an HttpModule Code
If you are a java guy like me, you need to learn little bit of c# programming. Install visual studio or Visual studio C# express as an IDE for compiling the code below.

using System;
using System.Security;
using System.Security.Principal;
using System.Web;
using System.Web.Security;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.IO;

namespace OamHttpModule {
class OamAuthenticator : IHttpModule {
public void Init(HttpApplication app) {
app.AuthenticateRequest +=(new EventHandler(this.Application_AuthenticateRequest));
app.PreSendRequestHeaders +=(new EventHandler
this.Application_PreSendRequestHeaders));
}

private void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (HttpContext.Current.Request.Headers["HTTP_OBLIX_UID"] != null)
{
NameValueCollection coll = HttpContext.Current.Request.Headers;
string midmsUser = coll["HTTP_OBLIX_UID"];
HttpApplication app = (HttpApplication)sender;

string[] roles = new string[1];
roles[0] = "viewer";
GenericIdentity id = new GenericIdentity(midmsUser, "Forms");
GenericPrincipal p = new GenericPrincipal(id, roles);
app.Context.User = p;
}
}
private void Application_PreSendRequestHeaders(object sender, EventArgs e) {
HttpApplication app = (HttpApplication)sender;

if (app.Response.RedirectLocation != null) {
if (app.Response.RedirectLocation.Contains("AccessDenied.aspx?Source") &&
app.User.Identity.Name == "Visitor") {
app.Response.Redirect("/_layouts/login.aspx?ReturnUrl=" + app.Request.RawUrl);
}
}
}

public void Dispose() {
}
}
}

Now, create a strong name key for this module. This key will be used later in webconfig, so SharePoint will honor this code. The snaps shot is taken from Visual C# express studio. Select the Project Properties :-


fig2.JPG


Enter the KeyName here.



From the dropdown select new and enter the Key file name (say OamHttpModule) in the popup box. Next build the solution. Building the solution will result a .dll file (say OAMHttpModule.dll). Now register this key in Window Assembly. From command prompt type "assembly". Drop the OAMHttpModule.dll to assembly window (shown below) from the solution area.


Right click to get "OamHttpModule" properties , note down the generated public key token.


This Public key token value will be used in webconfig file.

Step 2 : Web.config Changes
We have completed building the OAMHttpModule.dll. Let's include it webconfig so SharePoint will able to access it.
Step a : Include HttpModule in webconfigAdd HttpModule class name under <httpModules> tag

<httpModules>
:
:
<add name="OamAuthenticator" type="OamHttpModule.OamAuthenticator,
OamHttpModule,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=57773ac73696c406" />
</httpModules>

Mention the Public Key Token copied from Assembly window. SharePoint will not allow this code to run inside without this public key token.

Step b: Change the error display setting in webconfigCHANGE under <SharePoint><SafeMode… tag

<SafeMode MaxControls="200" CallStack=" false " DirectFileDependencies="10" TotalFileDependencies="50" AllowPageLevelTrace="false">
TO
<SafeMode MaxControls="200" CallStack=" true " DirectFileDependencies="10" TotalFileDependencies="50" AllowPageLevelTrace="false">

CHANGE under <system.web> tag

<customErrors mode="On" />
TO
<customErrors mode="Off" />

Step c: Change the trust level in webconfig so the HttpModule can be executed
In the web.config

CHANGE under <system.web> tag
<trust level="WSS_Minimal" originUrl="" />
TO
<trust level="WSS_Medium" originUrl="" />

Restart the IIS server.
2.OAM IntegrationI am assuming that you are familiar with Webgate setup for IIS server. After completing the Webgate set up for IIS (that hosts SharePoint), define appropriate URL policy for SharePoint on OAM access manager.

Let's test the setup.

Step 1: user enters the SharePoint URL http://mde-mossdev:87/ protected by Oracle's form authentication.



Step 2: The webgate then intercept the URL and check for the authentication policy. Since the authentication policy is defined as a form, it displays the configured form based authentication screen. User put his credentials; webgate then validate it and allow the user to access SharePoint URL.

Step 3: At this point our custom HTTPModule read the USER_ID from header (set by OAM after the authentication) and creates a GenericPrincipal for SharePoint and set the SSO token in the browser so user can have single sign on with other applications. Below is the screen, which shows the SP home page with the above said user already, logged in (see "Welcome Celuser1" in the screen top right hand side corner).



Yep, we are done ….