Tips & tricks for installing and running ICS products

Security Reverse Proxy with Connections - forcing all trafic through the interservice url

Tom Bosmans  20 April 2017 15:17:50
In a recent project, we are using IBM Datapower as a security reverse proxy to handle authentication and coarse grained authorization for Connections 5.5 .

The approach we follow is similar to what I have described here :

https://www-10.lotus.com/ldd/lcwiki.nsf/dx/IBM_Connections_v4.5_and_WebSeal_integration_col_alternative_approach

In short : you want to avoid that the interservice traffic passes through the reverse proxy (Datapower or Webseal , that is not relevant at this point).

The picture below shows that you want to have 2 paths of access :

- for users and api access etc : through your reverse proxy

- the internal , backend connections : through your http server

Image:Security Reverse Proxy with Connections - forcing all trafic through the interservice url

To do that , you need to make sure you have different values for the href/ssl_href and interservice values in LotusConnections-config.xml.

<sloc:href>
             <sloc:hrefPathPrefix>/wikis</sloc:hrefPathPrefix>
             <sloc:static href="https://connections.company.com" ssl_href="https://connections.company.com"/>
             <sloc:interService href="https://ihs.internal.com"/>
     </sloc:href>


You can see a lot of things here :

- you need to do this for ALL services defined in LotusConnections-config.xml

- all url's are https

- the interservice url is different from the static.

- the interservice url points to the HTTP server (or a load balancer pointing to the HTTP Servers)

- the static urls point to your reverse proxy (or the load balancer pointing to your reverse proxy)

- bonus points  : put the interservice url in different domain from the static urls, to avoid potential xss problems.

Some additional remarks :

- do not use the dynamicHost section, that is generally recommended when using reverse proxies

- set the forceConfidentialCommunitication flag to "true" .  ALWAYS.  You don't want to use http in these times, you always want to use https.

Now for the problem : although this should instruct Connections to use the internal http server for interservice requests, in reality, the backend still makes calls to the static urls.


That is very annoying : if you don't allow access from your back-end servers to the reverse proxy, everything will fail.  If you do not allow unauthenticated access through Datapower (or your reverse proxy), widgets don't render.

This becomes apparent for Widgets in the following manner :

[3/27/17 19:07:21:459 CEST] 00000149 IWidgetMetada W   com.ibm.cre.iwidget.widget.parser.InvalidWidgetDefinitionException: com.ibm.cre.iwidget.widget.parser.InvalidWidgetDefinitionException: org.xml.sax.SAXParseException: The element type "meta" must be terminated by the matching end-tag "".
[3/27/17 19:07:21:535 CEST] 00000149 IWidgetMetada W   com.ibm.cre.iwidget.widget.parser.InvalidWidgetDefinitionException: com.ibm.cre.iwidget.widget.parser.InvalidWidgetDefinitionException: org.xml.sax.SAXParseException: The element type "meta" must be terminated by the matching end-tag "".
[3/27/17 19:07:21:845 CEST] 000001c6 AbstractSpecF W org.apache.shindig.gadgets.AbstractSpecFactory SpecUpdater An error occurred when updating https://connections.company.com/connections/resources/web/com.ibm.social.ee/ConnectionsEE.xml. Status code 500 was returned. Exception: org.apache.shindig.common.xml.XmlException: The element type "meta" must be terminated by the matching end-tag "". At: (1,415). A cached version is being used instead.
[3/27/17 19:07:21:847 CEST] 000001c7 AbstractSpecF W org.apache.shindig.gadgets.AbstractSpecFactory SpecUpdater An error occurred when updating https://connections.company.com/connections/resources/web/lconn.calendar/CalendarGadget.xml. Status code 500 was returned. Exception: org.apache.shindig.common.xml.XmlException: The element type "meta" must be terminated by the matching end-tag "". At: (1,415). A cached version is being used instead.

This means that the back-end application (the WidgetContainer in this case) tries to retrieve the Widget configuration xml file, through the Reverse Proxy.  Because the Reverse Proxy does not allow unauthenticated acces, it presents a (html) login form .  That is interpreted as "invalid xml" .

Now by following the instructions here, to allow unauthenticated URI's through your reverse proxy, this can be resolved.  https://www.ibm.com/support/knowledgecenter/SSYGQH_5.5.0/admin/secure/t_secure_with_tam.html

If you don't allow access from your backend to your reverse proxy, you're still out of luck though.  And that previous part does nothing for any custom widgets or third party widgets you may have deployed (eg. Kudos Boards)

Core Connections

There is an undocumented solution for this, luckily, that you may get through support.

You need to edit opensocial-config.xml , in your Deployment Manager's LotusConnections-config directory.

After this line :


<external-only-access-exceptions>none</external-only-access-exceptions>

Add these lines :


     <proxyInterServiceRewrite name="opensocial" />
     <proxyInterServiceRewrite name="webresources" />
     <proxyInterServiceRewrite name="activities" />
     <proxyInterServiceRewrite name="bookmarklet" />
`        <proxyInterServiceRewrite name="blogs" />
     <proxyInterServiceRewrite name="communities" />
     <proxyInterServiceRewrite name="dogear" />
     <proxyInterServiceRewrite name="files" />
     <proxyInterServiceRewrite name="forums" />
     <proxyInterServiceRewrite name="homepage" />
     <proxyInterServiceRewrite name="mediaGallery" />
     <proxyInterServiceRewrite name="microblogging" />
     <proxyInterServiceRewrite name="search" />
     <proxyInterServiceRewrite name="mobile" />
     <proxyInterServiceRewrite name="moderation" />
     <proxyInterServiceRewrite name="news" />
     <proxyInterServiceRewrite name="profiles" />
     <proxyInterServiceRewrite name="sand" />
     <proxyInterServiceRewrite name="search" />
     <proxyInterServiceRewrite name="thumbnail" />
     <proxyInterServiceRewrite name="wikis" />


Sync your nodes, and restart everything.  All trafic for the standard widgets (eg. on Homepage or in Communities) will now go render correctly.
Note that this is not valid for CCM nor for Mobile, these have separate settings in library-config.xml and mobile-config.xml respectively where you can select to "use interservice url" .
For Docs, the configuration is done in the json configuration files .  I'm not going into these details here.

Custom or third party Widgets Connections

So great, the core Connections widgets are now rendering, and all trafic for them is now going through the interservice URL you defined .

There is however the small problem of custom widgets.  These are not handled by the rules in opensocial-config.xml .
We use Kudos Boards (http://www.kudosbadges.com/subpages/Kudos%20Boards?OpenDocument), but this next section is valid for all (most) custom or third party widgets you need to behave properly.

There's 2 more files to edit :


  • service-location.vsd: to allow you to edit LotusConnections-config.xml
  • LotusConnections-config.xml


And you need widget-config.xml , and still need to edit opensocial-config.xml .

widget-config.xml


Find the custom widget's configurationn in widget-config.xml.  In this example, we're looking at Boards (this is a sample, not actual widget definitions !).
You need the defId value here, so in our case, Boards.

<widgetDef defId="Boards" description="Kudos Boards widget" primaryWidget="true" modes="fullpage edit search" themes="wpthemeNarrow wpthemeWide wpthemeBanner" url="/kudosboards/boards.xml" showInPalette="true" loginRequired="true"/>

service-location.vsd


In service-location.vsd , add a line for every custom/third party widget.  You need to use the defId name from widget-config.xml in the previous step



The values here need to match the Widget definition in widget-config.xml, the service reference in LCC.xml, and the proxyInterServiceRewrite name in opensocial-config.xml.

LotusConnections-config.xml


In LotusConnections-config.xml, you then add a serviceReference entry for every custom (or third party) widget.  To be able to do that, you must have changed the service-location.vsd .



<sloc:serviceReference enabled="true" serviceName="Boards" ssl_enabled="true">
     <sloc:href>
             <sloc:hrefPathPrefix>/kudosboards</sloc:hrefPathPrefix>
             <sloc:static href="https://connections.company.com" ssl_href="https://connections.company.com"/>
             <sloc:interService href="https://ihs.internal.com"/>
     </sloc:href>
</sloc:serviceReference>

opensocial-config.xml


Finally, in opensocial-config.xml, add the rule for your custom widget, after the rules you added earlier.


<external-only-access-exceptions>none</external-only-access-exceptions>
     <proxyInterServiceRewrite name="opensocial" />
     ...
     <proxyInterServiceRewrite name="thumbnail" />
     <proxyInterServiceRewrite name="wikis" />
     <proxyInterServiceRewrite name="Boards" />

That is it.  You now sync your nodes, and restart everything.  Your custom widget will now work correctly .



If all else fails ...


Now there is a simpler solution to all of this .  You can use your /etc/host file to just match the public url (connections.company.com) to the IP address of the internal http server.  
I don't particularly like this solution, though.  It is difficult to maintain , and it probably breaks your company's standards and rules.