IBM Connections application development state of the union – part 6

Part 5 was about extensions/apps on-premises and this – probably final post – will be about extensions for IBM Connections Cloud. There are different ways to extend IBM Connections Cloud – one is to add links to the app menu and another is to add actual UI extensions to the applications within IBM Connections. This post is about the latter (although the observations about the administration UI applies to both). To get it out of the way from the beginning I might as well say it flat out. IBM has really missed the mark here. The extensibility mechanism for IBM Connections in Cloud is close to unusable from my point of view. Let me explain…

Basically the extension mechanism for cloud is an iframe and you may only extend Communities which is so wrong to begin with. As mentioned previously IBM Connections is a piece of social software that focus on people and not being able to extend Profiles is baffling to me. Using a clumsy UI in the administration portal you can upload a JSON file describing the extension which in turn will make the extension show up in the main UI. The smallest file I could make work is 34 lines of JSON but basically I could do away with 3 lines. Almost all of the JSON I upload is simply cruft that seems to carry over from the on-premises widget container and as I really cannot change it why should I specify it? In essence I can only change the following 3 parameters:

  • defId – seems to be an ID of the widget
  • url – the URL to set into the iframe
  • height – the height of the iframe

Part of the JSON I upload is the widget ID. I have to specify the ID of the widget (defId) but there is no check whether it’s used. Using an already used ID is allowed but only one of the widgets with the same ID shows up which is an issue as this is an obvious copy/paste error on the users part. Also the widget is added to the community page using the defId as the title but shown in the administration UI using a “name” parameter from JSON which is pretty confusing. Part of the JSON I upload is also the actual iWidget that creates and builds the iframe. I can specify my own iWidget description and the only thing that makes it not work is the ajaxProxy rejecting it making the UI fail when users load the community page. There is no upload time check. Often times an invalid JSON file only makes the UI do nothing – there is no response as to what might be wrong.

Sigh…

Once the JSON is uploaded I get an iframe of a static height with a URL set into it. The height is one thing that makes this extension mechanism hard to work with for production apps. Often times the height of the content cannot be decided at deployment time but is only known at runtime and unfortunately there is no way to change the iframe height at runtime. At least nothing which is obvious and/or documented. But now we have an iframe set the URL specified in the application JSON. The iframe is sandboxed with the following policy: “allow-same-origin allow-scripts allow-popups allow-forms”. This restricts the extension and basically it may only do the following:

  • Run JavaScript
  • Make xhr requests to the server it was loaded from (same origin)
  • Open a new window/tab in the browser

There is no way for the widget to even talk to IBM Connections itself – not even the IBM Connections API. The widget may basically show static / server side generated HTML and run JavaScript. The JavaScript may make xhr requests to the server it was loaded from. That’s it.

When the widget loads it may ask the surrounding page for a widget context by registering a message listener and posting a message to the parent page (parent.postMessage). The context looks like this:

{
   "source": {
      "resourceId": "ff7dd8b4-95d6-4fb4-f094-edb52e5d8eee",
      "resourceName": "Some Community Title",
      "resourceType": "community",
      "orgId": "12345678"
   },
   "user": {
      "userId": "87654321",
      "orgId": "12345678",
      "displayName": "John Doe",
      "email": "jdoe@example.com"
   },
   "extraContent": {
      "canContribute": "true",
      "canPersonalize": "true"
   }
}

From the context the widget can figure out who the user is and what community the user is in. The problem is however that the user information is unusable as there is no way my application server can trust this user information. As the context is not verifiable in any way there is no way for my server to trust the information it receives from the extension. The only way to convey user identity to my server is by using SAML and assume that a SAML assertion dance is performed when the iframe contents is loaded so the user has a session cookie relationship with my server. But this is doable – I now know the user identity based on the SAML dance.

Next thing is to make sure the user is actually a member of the community he/she is sending to my server – but oh – there is no way to decide this. My server side code cannot make requests on behalf of the user back to IBM Connections without the user having already performed an OAuth dance and authorized my application to IBM Connections. I could tell the user that we might not have tokens for him/her but it yields a crappy user experience. Plus any authorization granted expires from time to time (at least every 90 days). Also there is no organization wide OAuth authorization capabilities in IBM Connections Cloud like is the case for Google or Microsoft plus there is no super-user for IBM Connections so we’re pretty stuck here.

Now this is pretty bad and combining these things basically makes it impossible to create any kind of customer or ISV solution with a decent user experience. At least if the context is important and the contents is not static.

So what do we do about it? Well IMHO the solution is pretty easy and simple which makes it even worse that IBM decided to ship this capability. Let me suggest the following points:

  • Administration UI
    Fix the administration UI including the widget JSON I have to upload. Only ask for the stuff that actually matter and induce the rest if not specified. If the uploaded file doesn’t validate tell me – maybe even provide a clue as to what’s missing…
  • Make the context verifiable
    When I register a widget add an option to indicate that my server needs to verify the information in the context (the JSON blob above). If I check the box generate a set of asymmetric keys and provide me one of the keys. Now the JSON context could be signed with the IBM Connections part of the key making my server capable of verifying that the information indeed came from IBM Connections. And since it’s asymmetric there is no way for my server to impersonate IBM Connections. Oh and this would make the information in the context trustable even if the customer is not using SAML.
  • Making calls back to IBM Connections possible
    When I register a widget add an option for me to indicate that my server needs to make calls back to IBM Connections on behalf of the user. For additional credits allow me to specify which parts of the IBM Connections API my server may use. In combination with the asymmetric key pair above this option would include an encrypted opaque token in the JSON context blob. This token could be used by my server to authenticate my server and the request back to IBM Connections. It could be a set of automatically generated OAuth tokens but doesn’t need to be. This is a secure solution as we already have a key pair in place so the token could be encrypted using the IBM Connections part of the key pair so that the widget code in the browser cannot use it. Only the server with the matching key may decrypt the token and use it for the IBM Connections API.

Now I’m no security expert but this should be secure and pretty easy to implement. With a single sweep it would make widgets in IBM Connections Cloud way more powerful than widgets on-premises and would make them much easier to develop. Only thing left then is making it possible to adjust the height at runtime but I’ll let that slip for now as a basic oversight in the design of the extensibility mechanism and assume this capability will be available soon anyway.

</rant >

I have a small IBM Connections Cloud community apo on Github if you would like to see a minimal example: IBM Connections Cloud Community App Example

Websphere Application Server Security – make sure file based auth continues if federated repository is unavailable

While looking for another tidbit of information on Google I found this very interesting setting in a WAS FAQ (Q & A: Frequently asked questions about WebSphere Application Server security). That fact that access to the Integrated Solutions Console (ISC) would stop if a LDAP directory was unavailable even though the ISC admin account was local has been bothering me for a while. It was nice to see that this fact which has been irritating me for a while (when it isn’t set) is solvable.

7. When using a federated repository, is there a way to ensure that my file-based registry will continue to function when a LDAP server is down?

Yes, there is a configuration option that enables the authentication to continue if one or more other registries are down, as long as the ID is found in one of the registries that are still up and functional. The federated repository configuration command to permit this is:

$AdminTask createIdMgrRealm
     -name ibmRealm -allowOperationIfReposDown true

More information can be found in the Information Center article: IdMgrRealmConfig command group for the AdminTask object.

Is the security of the Notes/Domino Java implementation questionable? (security vulnerability in the Notes/Domino Java API)

DISCLAIMER
The information below is provided as-is and I cannot be held liable for any damages, direct or indirect, caused by the information in this post or based on the below findings. The information here is offered in the interest of full disclosure. I have been working with IBM Lotus to diagnose and pinpoint the exact consequences of the below findings since May 2006.

Description

As you might know a central security measure in the Notes/Domino security infrastructure is the difference between restricted and unrestricted operations. Only users granted unrestricted access may perform sensitive operations such as disk I/O and manipulating the system clock. The implementation flaw I found in the Java API of Notes/Domino allows me to circumvent these restrictions and hence circumvent the security settings of the Domino server.

As such the guidelines given in this post could also be used to fully replace the Java API and perform additional operations without the knowledge of the owner of the Domino server or Notes client.

Prerequisites

  • Disk access to the Domino server or Notes client or be able to write an agent or other piece of code that may accomplish the task for you.

Steps to reproduce

Below I describe the steps necessary to circumvent the SecurityManager and/or hide malicious code.

  1. Obtain a copy of the Notes.jar file from the Domino server and copy it to a local workstation.
  2. Unpack the archive using the jar-command.
  3. Decompile the code (I used the JODE version 1.1.2-pre2 decompiler from http://jode.sourceforge.net)
  4. Using Eclipse, or similar, edit the code in the constructor of the lotus.notes.AgentSecurityContext class as shown below:
    public AgentSecurityContext(ThreadGroup threadgroup, boolean bool) {
      m_restricted = bool;
      m_file_read = true;
      m_file_write = true;
      m_net_access = true;
      m_class_loader = true;
      m_extern_exec = true;
      m_native_link = true;
      m_system_props = true;
    
      try {
        AgentSecurityManager agentsecuritymanager = (AgentSecurityManager) System
          .getSecurityManager();
        if (agentsecuritymanager != null)
        agentsecuritymanager.newSecurityContext(this, threadgroup);
       } catch (ClassCastException classcastexception) {
         /* empty */
       }
    }
    
  5. Compile the class and replace the version from the unpacked Notes.jar
  6. Create a new Notes.jar with the manipulated code and replace the Notes.jar on the server. You might have to shutdown the server/client to be able to replace the file.

Using a Domino server in a virtual machine I created a text file called readme.txt in the root of the c-drive on the server and ran the below agent as scheduled on the server. The agent tries to read data from the readme.txt file in the root of the c-drive on the local server (Windows 2000 Server). As expected the JVM throws a java.lang.SecurityException using the Notes.jar supplied with the Domino installation. If I replace the Notes.jar supplied by IBM with my manipulated Notes.jar the agent runs to completion without any incident thus circumventing the security measures put in place by the Domino server.

import lotus.domino.*;
import java.io.*;

public class JavaAgent extends AgentBase {
   public void NotesMain() {
      try {
         Session session = getSession();
         AgentContext agentContext = session.getAgentContext();

         System.out.println("Starting to run agent...");
         FileReader r = new FileReader("c:\readme.txt");
         StringBuffer buffer = new StringBuffer();
         char[] data = new char[128];
         r.read(data, 0, 127);
         buffer.append(data);
         System.out.println("File data: " + buffer.toString());
         r.close();

      } catch(Exception e) {
         e.printStackTrace();
      }

      System.out.println("Done running agent...");
   }
}

Consequences

One thing is being able to circumvent the restricted/unrestricted security measure of the Domino server. Another thing is that this can be done without the administrator or users knowing about it.

As mentioned above you might even be able to use the steps to replace some of the core classes (such as the class implementing the Document interface). By doing this you could have the manipulated class send you a copy of all e-mails generated using the Document.send() method or to add a specific user to all reader/author fields being written to documents.

This should be possible since all the Domino API types are interfaces and as such are open for re-implementation. It does however also mean that you have to manipulate the factory methods of the API.

I must stress that I haven’t tried this myself – yet…

Suggestions

Issues like this could be avoided by digitally signing the Notes.jar file provided by IBM and have the Domino server and Notes client verify the signature of the jar-file before loading classes from it. Since a lock is placed on the jar-file by operating system once read (at least on Windows), the impact on performance should be minimal since the jar-file only needs to be checked once.

As an aside I can mention that some of the jar-files provided with the Domino server/Notes client are digitally signed by IBM already:

  • ibmjcefips.jar
  • ibmjceprovider.jar
  • ibmpkcs11.jar
  • ibmpkcs11impl.jar

Resources

Potential IBM Lotus Notes information leakage on port 1352

Andrew Christiansen contacted IBM® Lotus® to report a potential vulnerability
in unauthenticated transactions using the Notes Remote Procedure Call (NRPC)
protocol on port 1352.
The advisory address is as follows:
http://www.fortconsult.net/artikler/advisories.php

The NRPC protocol uses an unauthenticated transaction to look up a user
who is not yet authenticated so that the user can fetch their ID file during
Notes® setup. This transaction is optionally used when a user is first
registered or when a roaming user connects from a new client."

IBM Lotus Notes information leakage on port 1352 via the Lotus Domino Support RSS feed.

Security threats of syndicated content

There are a number of interesting discussions going on at the moment about the inherent threats of syndicated content sparked by a presentation at the Black Hat 2006 event. I like the way Don Park puts it in his “Comment on Microsoft Embracing RSS“-post:

"If you subscribe to 1000 feeds, you are hanging on a chain with 1000 links. Each of those 1000 links (feeds) are potential targets for hackers to attack to gain control over its content. All they need is one vulnerable feed hosting server to change what is delivered to your desktop."

Something to think about – especially when thinking about how Notes/Domino 7.0.2 will be able to deliver RSS feeds to your employees. I recommend the above post or the Dons other post (Syndicated Vulnerability) to get started.