Wednesday, December 3, 2014

Major achievement! Single Sign On through BusinessObjects Restful Web Services

If you've ever tried to implement Single Sign On using Windows AD and Kerberos, you'll understand why the title of this post is Major Achievement!  Heck, even a blogger from Microsoft Support will tell you:
Kerberos is one of the more complicated technologies we deal with at Microsoft support. It is complex and can be utilized in highly customized ways between clients and servers which adds to the difficulty in troubleshooting. Application specific implementations are commonly unique in ways which aren’t documented well.  An additional part which makes troubleshooting Kerberos so very difficult though is the fact that it typically just works without problems. So no ‘under the hood’ knowledge is needed in the first place. 
I've implemented Kerberos a couple of times, and it has always been a major deal.  Luckily, I've been able to declare victory in the end and jump up and down on the top of my desk in a victory dance once the battle is won  (okay, the dance was in my head lol).

Hopefully these instructions will save you some pain!

**One fairly LARGE assumption I'm making is that you have already achieved a Kerberos SSO for normal BuisnessObjects login.  If you haven't done that, here is some documentation from SAP.  You'll want to refer to the original article written by Steve Fredell.**


The WACS


Since the BO RESTful Web Services uses the BO Server named "Web Application Container" or "WACS".  The WACS has to be configured for Kerberos.  If go to the properties, you will see some configuration fields related to Windows AD and Kerberos, but they are all for services other than the RESTful Web Service.  Kerberos settings are conspicuously absent from that section!



So what you have to do is modify the following file:

<Install Location>\SAP BusinessObjects\SAP BusinessObjects Enterprise XI 4.0\java\pjs\services\RestWebService\biprws\WEB-INF\web.xml

You only have to specify your domain (realm) and SPN.  The other settings can be left untouched.



The one thing that remains a mystery to me is why I did not have to specify the location of my krb5.ini and bsclogin.conf files.  For my BI LaunchPad configuration, I specified this in the Java Options of the Java tab in the Tomcat Configuration like this:

-Djava.security.auth.login.config=C:\Windows\bsclogin.conf
-Djava.security.krb5.conf=C:\Windows\krb5.ini
-Dcom.wedgetail.idm.sso.password=xxxxxxxxxxx

I finally stumbled onto this forum post. With some deduction from the info there, I found you have to modify the command line in the properties of the WACS to add the following lines (I'm not sure if location matters, but mine is after the -Xrs):

Dcom.wedgetail.idm.sso.password=yourpassword -Djcsi.kerberos.maxpacketsize=0

The maxpacketsize is the max packet size it will use for UDP before using TCP. Changing this to 0 will force the use of TCP only, which allows for bigger packet sizes.  This is important if your users are members of many AD groups, because the full membership is passed along with the token.

This still doesn't explain how the WACS knows where to find the krb5.ini and bsclogin.conf files, but mine works.  All I can figure is that my files are in the correct default location, or there is some reference to Tomcat somewhere?

The code


My implementation was done in ASP.NET, so I'll give some code snippets from that standpoint.

The documentation from SAP BusinessObjects for SSO for the RESTful web services is in a weird location.  It is found in the SAP Crystal Reports RESTful Web Services Developer Guide.  The particular version of this doc I used was 4.1 Support Package 3 - 2014-04-03.  Search for "adsso" in that document and you will find a section "To get a logon token using an Active Directory Single Sign-On (AD SSO) account".


A must have tool is the Advanced REST client from Google that plugs into Chrome as an app.  Your first order of business should be to install that.   The irony is that I got a logon token from day one using the Advanced REST client, but it took me weeks working off and on to get everything else straightened out!  If you are lucky like me, you can just paste http://yourservernamehere.com/biprws/logon/adsso into the Advanced REST client and walla, you get a logon token!  If not, you'll have some basic kerberos troubleshooting to do, which is beyond the scope of this article.

Here is the C# code from an .aspx web form that is used to formulate the request:

string url = "http://yourservernamehere.com/biprws/logon/adsso";
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(url);
myRequest.Method = "GET";               
myRequest.Accept = "application/xml";
myRequest.ContentType = "text/plain; charset=utf-8";
myRequest.KeepAlive = false;               
//informational for debugging to verify the user being used for kerberos--this should be you!              
userName = HttpContext.Current.User.Identity.Name;
 
myRequest.UseDefaultCredentials = true;
 
myRequest.PreAuthenticate = true;                 
 
HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
 
//get the X-SAP-LogonToken from the header
this.LoginToken = myResponse.Headers["X-SAP-LogonToken"];



In the web.config file for your project, you will need the following:



  </appSettings>
<system.web>
<compilation targetFramework="4.0" debug="true"/>
<authentication mode="Windows"/>
<identity impersonate="true"/>
<customErrors mode="Off"/>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
</system.webServer>
</configuration>

If you don't include the validateIntegratedModeConfiguration="false", you may get an error from IIS that tells you have an incompatible configuration! Now the trick to get this code to work is to get IIS and ASP.NET to pass along the kerberos ticket.  IIS is a "man in the middle" between the client and the BO server that must be configured to forward kerberos tickets.  That is why the Advanced REST client is an important troubleshooting tool, because it bypasses the IIS middle piece, and because it returns full error message details that ASP.NET does not expose in it's error messages.

IIS the Middle Man


Step 1:  Decide on IIS Express or local IIS


I ended up getting both to work.  The simplest route is to use IIS Express, so I'll describe that scenario first.  

IIS Express

This is the web server that is installed with Visual Studio and used by default for running and debugging from VS.  It does not have the GUI configuration tools for its settings that normal IIS does.

The settings are located in the following file:  My Documents\IISExpress\config\applicationhost.config

Here is how I configured it:


        <security>
        <access sslFlags="None" />
        <applicationDependencies>
        <application name="Active Server Pages" groupId="ASP" />
        </applicationDependencies>
        <authentication>
        <anonymousAuthentication enabled="false" userName="" />
        <basicAuthentication enabled="false" />
        <clientCertificateMappingAuthentication enabled="false" />
        <digestAuthentication enabled="false" />
        <iisClientCertificateMappingAuthentication enabled="false">
        </iisClientCertificateMappingAuthentication>
        <windowsAuthentication enabled="true">
        <providers>
        <add value="Kerberos" />
        <add value="Negotiate" />
        <!--<add value="NTLM" />-->
        </providers>
        </windowsAuthentication>
        </authentication>
        <authorization>
        <add accessType="Allow" users="*" />
        </authorization>

IIS Express runs under your Windows Account, which gives it broad privileges.  Running under your user also eliminates some complexity that is present in normal IIS where specialized accounts are used.  Unless I forgot something, that should be all you need!

Local IIS

You have to right click on Visual Studio and choose "Run as Administrator" to be able to use local IIS.  Right click on your project and choose "Properties", then go to the "Web" section and change the server to Local IIS like this:


Because IIS is the man in the middle, we have to run the website as a domain user, the domain user being a service account that was previously used to create SPNs.  The domain account must also be given the right to delegate in Active Directory as shown in this screen (this should already have been configured under the premise that you have a working BI LaunchPad AD configuration):




Your website must be configured to use an Application Pool, and the Application Pool must use the domain user service account mentioned above.  Set the identity as seen below, and verify that the Managed Pipeline Mode is "Integrated"



Finally, you must have the correct authentication providers for your website.  There are 3 different levels in the hierarchy of your website, and the providers must be set at each level.  I turned on Negotiate and NTLM at the root level, and then just turned on Negotiate at the Default Web Site level and at the lowest level (RestDemo application level in my case).  You could probably remove NTLM at the root level, because it should be inherent to Negotiate.  The way Negotiate works is that it first tries Kerberos, and if that fails, it falls back to NTLM.  Click the Configuration Editor for all 3 levels as seen below. Also verify that "UseAppPoolCredentials" and "UseKernelMode" are true:





Whew!  That should do it!  Now cross your fingers and say a little prayer and run your application!

If you need to troubleshoot more, start with this article: Explained: Windows Authentication in ASP.NET 2.0, then move on to the Kerberos articles out there such as this one:  Kerberos for the Busy Admin

--Craig

2 comments:

  1. Great Work Craig !!!!!,

    Thank you for sharing the info on Single Sign On using Windows AD and Kerberos using WACS

    Appreciate you for the commendable work

    Regards,
    Venu.Kavuru

    ReplyDelete