Making the Generic Connector Framework Even More Generic

I did a presentation on this for the developer's lounge at Summit-and promised I would have it up by today. Hopefully someone will find it useful.


Sungard HE's Luminis way of connecting to other external services is called CPIP (Campus Pipeline Integration Protocol). For each external service you want to connect to you develop a CPIP connector. To make the task of developing CPIP connector's easy on their client, Sungard has created something called the Generic Connector Framework. The GCF is a CPIP connector that connects to a service based on two configuration files.

As an overview, to create a CPIP adapter for a system, you would:

  1. Add the system name to es.systems field in Luminis LDAP
  2. Load external system credentials into all user accounts that will be using that system.
  3. Create a properties file and xml file for that system in $CP_ROOT/products/sso/config
  4. Update the cpipconnector.properties file to list your CPIP connector's property file.

We use the GCF extensively here at Hofstra, but one of the downsides to it we discovered early on was that if you had multiple external systems that used the same exact credential set you would have to create separate connectors for them. Most schools are going to have multiple systems that use a centralized authentication service, so this seemed incredibly inefficient - especially when you consider that you're storing the same external credentials over and over again for each user.

The way we solved this was to create an even more generic CPIP connector that took in parameters that described the external system using the GCF as a base.

At Hofstra, many, many of our web based applications authenticate against Novell LDAP - so we created a Novell CPIP connector the way you would create a connector normally using the steps above. But instead of having the connector submit off to a URL or use specifically named form elements, we made these all configurable based on cookies set inside the portal. Let's look at some concrete code. Although there are a number of fields in the properties file, the one that we're really interested in is systemname.pickup.response-that's where the meat is.


novell.pickup.response           =              <html>\
         <head>\
                      <meta http-equiv="cache-control" CONTENT="no-cache">\
                      <meta http-equiv="Pragma" CONTENT="no-cache">\
                            <meta http-equiv="Expires" CONTENT="-1">\
                       </head>\
          <body bgcolor="#ffffff"> Loading...\
                <script language="JavaScript">\
                FormAction = GetCookie("CPIPFORMACTION");\
                Username = GetCookie("CPIPUSER");\
                Password = GetCookie("CPIPPASS");\
                Hidden = GetCookie("CPIPHIDDEN");\
                document.writeln("<form action='" + FormAction + "' method='post' name='doAuthen'>");\
                document.writeln("<input type='hidden' name='" + Username + "' value='~{_USERNAME}'>");\
                 document.writeln("<input type='hidden' name='" + Password + "' value='~{_PASSWORD}'>");\
                if (Hidden != null)\
                {\
                      HiddenList = Hidden.split("|");\
                      for (i = 0; i < HiddenList.length; i++)\
                      {\
                           NVPair = HiddenList[i].split(",");\
                             Name = NVPair[0];\
                             Value = NVPair[1];                      \
       document.writeln("<input type='hidden' name='" + Name + "' value='" + Value + "'>");\
                      } \
               }\
                document.writeln("</form>");\
                document.forms[0].submit();\
           </script>\
         </body>\
</html>

Looking at the code above, you'll notice that each line ends with a '\'. This is the standard notation to let CPIP know that all that all this data that runs across multiple lines is part of the
novell.pickup.response property(seen at the top). You'll also notice a place that refers to ~{_USERNAME} and one that refers to ~{_PASSWORD}. This is where the GCF will insert the username and password the user logged in with. You might also notice some very standard JavaScript code for decoding cookies which is how we pass parameters in from Luminis channels.

Let's look at the body. You'll see we decode four different cookies. Each one of these represents a parameter being passed into the CPIP connector. The first one is the form action - the location this form is suppose to submit to.

The second one is the name of the username field in the form we are authenticating to. Like many websites, not all of our authentication forms use the same names for the username and password fields(it would be so much easier if they did!).

Similarly, the third parameter is the name of the password field in the form that we are submitting.

Lastly, we decode a cookie named 'HIDDEN' that is a bit more complicated than the other parameters. Some authentication forms need extra form fields in order to work correctly. These extra field names (and their associated values) are stored in this cookie. Since the HIDDEN cookie can contain several form fields, they are separated insidethe cookie by a '|' and each name-value pair is delimited by a comma.

Once we have all that information, its relatively simple to build
our form and auto-submit it.

That was the hard work-now we'll see how this is triggered from inside a channel in Luminis.



<SCRIPT LANGUAGE="JavaScript">

function SetCPIP()
{
SetCookie("CPIPUSER", "user", null, "/");
SetCookie("CPIPPASS", "pass", null, "/");
SetCookie("CPIPFORMACTION", "https://wwww.whatsamatta.edu/testauth.html", null, "/");
SetCookie("CPIPHIDDEN", "position,faculty");
}
</SCRIPT>

<A HREF="https://my.whatsamatta.edu/cp/ip/login?sys=novell&url=null" TARGET="_blank" on Click="SetCPIP()">Click Here!</A>

In the above example, you have some standard JavaScript set-cookie code.

When the user clicks the link, CPIP is invoked at the Whatsamatta U. portal site. But a function is also invoked that sets up the cookies for the CPIP connector we developed above. They include where the form should submit to(in this case the Whatsamatta U. main website) the names of the username and the password fields, and a single hidden form field named 'position' that has a value of 'faculty'.

If anyone has any questions about the code, let me know!

P.S. One thing you'll notice is that if you have multiple CPIP connectors running on a single tab, you'll have to create multiple SetCPIP() functions. To avoid naming collisions you would alter the name of this function slightly on a per channel basis (usually I insert the name of whatever I'm CPIPing to). During the developer's lounge presentation, John mentioned that after I had first sent him this code a few weeks back, he realized a better way to avoid naming collisions would be to generalize out the SetCPIP function so it would take parameters, and then build this into nested-tables.xsl (definitely a great idea). He's probably not too busy or anything (*grin*) but hopefully he'll post the mod when he gets a chance :-)

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

right hand click

Is this a vaild limitation:

If a user's using firefox then opening a cpip link in a new tab won't work as this requires a right hand click? I believe the onClick event only works with a left hand click?

cheers

Luminis credentials

Hi Brian,

Does your Luminis system also authenticate against the Novell LDAP and use the same credentials as your other applications?

At our school, the plan is to have Luminis and most other applications(except INB and SSB) authenticate against an external LDAP. So, in our case, I guess it would be easier to use system credentials/sync password as suggested in the following thread:
http://www.lumdev.net/index.php?q=node/357

Any suggestions/comments ?

Shyam

RE: Luminis Credentials

Yes-we're using EAS against Novell LDAP for authentication-so it would totally make sense to use system credentials(I wrote this long before I realized you could do that to be honest). In your case I would recommend using system credentials with the connector I describe in this article, this way you can dynamically configure other elements of your CPIP connector such as destination, form element names, etc.). At some point I should update this article to use system credentials-just never got around to it.

Syndicate content