cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

Community Tip - You can change your system assigned username to something more personal in your community settings. X

How to Display a Mashup in an iFrame in a 3rd-Party App from ThingWorx 8.0?

sharmon
12-Amethyst

How to Display a Mashup in an iFrame in a 3rd-Party App from ThingWorx 8.0?

Summary

ThingWorx help has a good article on how to configure ThingWorx to allow a mashup to be displayed inside an iFrame on a third-party application. For example, you might want to contextualize business data inside a Microsoft Dynamics, SAP, Salesforce, or ServiceMax work order by including a ThingWorx mashup right there on the work order in your CRM tool. Your users get the benefits of ThingWorx, without having to leave the application that organizes their service workflows.

The instructions linked above help you configure what's sent back in the x-frame-options header. The web development community is moving beyond the x-frame-options header, though, and is phasing in the use of Content Security Policies, instead. As I'll demonstrate below, it appears ThingWorx 8.x is moving in that direction, too. ThingWorx now sends a ​content-security-policy ​header with a value of, "frame-ancestors 'self'".

I've followed the configuration guidelines from the help article, "Allowing Embedded Mashups in iFrames." The x-frame-options header is coming back as expected, that is, "ALLOW-FROM https://friendly-site.example.com."

In Firefox, the new content-security-policy header is causing me to get an interesting message in the console - "Content Security Policy: Ignoring ‘x-frame-options’ because of ‘frame-ancestors’ directive." In Chrome, I get, "Refused to display 'https://myinstance.thingworx.com/Thingworx/Runtime/index.html#mashup=Demo.Chevron.Main&appKey={{my-app-key}}&x-thingworx-session=true' in a frame because an ancestor violates the following Content Security Policy directive: "frame-ancestors 'self'".

Here's what the iFrame looks like in Firefox inside the page on the 3rd-party application:

Customer Asset_ BluePump001 - Firefox Developer Edition.png

Here's my question - how do I configure ThingWorx to send something other than, "frame-ancestors 'self'," in the content-security-policy header?

Details

Environment

  • ThingWorx 8.0.2-b67
  • Tomcat 8.5.13
  • Google Chrome Version 60.0.3112.113 (Official Build) (64-bit)
  • Firefox Developer Edition 56.0b8 (32-bit)
  • Postman for Chrome Version 5.2.0

Configuration

I followed the instructions in the ThingWorx help article linked above. Here's the relevant section from web.xml for my Tomcat instance:

<!-- CUSTOM FILTERS -->

  <filter>

    <filter-name>httpHeaderSecurity</filter-name>

    <filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-class>

    <async-supported>true</async-supported>

    <init-param>

      <param-name>antiClickJackingEnabled</param-name>

      <param-value>true</param-value>

    </init-param>

    <init-param>

      <param-name>antiClickJackingOption</param-name>

      <param-value>ALLOW-FROM</param-value>

    </init-param>

    <init-param>

      <param-name>antiClickJackingUri</param-name>

      <param-value>https://friendly-site.example.com</param-value>

    </init-param>

  </filter>

  <filter-mapping>

    <filter-name>httpHeaderSecurity</filter-name>

    <url-pattern>/*</url-pattern>

    <dispatcher>REQUEST</dispatcher>

  </filter-mapping>

          

Headers Returned with Various Requests

I think the content-security-policy header is new in ThingWorx 8.x, and that ThingWorx is setting the value of that header. I'll show why in the table below. I made three GET requests from POSTMan:

  • A mashup in ThingWorx 8.0.2-b63
  • A mashup in ThingWorx 7.0.1-b482
  • A request for the Tomcat start page (no ThingWorx requests)

Here are the various headers I got back:

HeaderMashup Request-TWX 8.0.2-b63Mashup Request-TWX 7.0.1-b482GET Tomcat 8.5.13 Front Page
accept-rangesbytesbytestext/html;charset=UTF-8

content-length

52655281N/A
content-security-policyframe-ancestors 'self'N/AN/A
content-typetext/htmltext/htmlN/A
dateWed, 06 Sep 2017 12:17:08 GMTWed, 06 Sep 2017 12:17:15 GMTWed, 06 Sep 2017 12:17:11 GMT
etagW/"5265-1504669330000"W/"5281-1504699189000"N/A
last-modifiedWed, 06 Sep 2017 03:42:10 GMTWed, 06 Sep 2017 11:59:49 GMTN/A
x-content-type-optionsnosniffN/Anosniff
x-frame-optionsALLOW-FROM https://friendly-site.example.comSAMEORIGINALLOW-FROM https://friendly-site.example.com
x-xss-protection1; mode=blockN/A1; mode=block
serverN/AApache-Coyote/1.1N/A
transfer-encodingN/AN/Achunked

Keep in mind - I configured the Tomcat 8.5.13 server to return the value you see in x-frame-options above.I didn't change web.xml on the 7.x instance.

From the experiments in the table above, I've drawn the following conclusions:

  • ThingWorx 8.x returns a content-security-policy header. ThingWorx 7.x does not. The header is therefore new in ThingWorx 8.x.
  • The request for a ThingWorx 8.x mashup returned a content-security-policy header, but the request to the Tomcat 8.5.13 server hosting in did not. ThingWorx 8.x is therefore setting the header value, and then returning it. It's not being created at the Tomcat level.

Different Browsers Handle the content-security-policy Header Differently

I experimented with different browsers, because they handle headers differently. The Mozilla Developers' Network has a table that lists how different browsers handle various values of the content-security-policy header:

Content Security Policy (CSP) - HTTP _ MDN.png

Temporary Workaround

Luckily, Internet Explorer ignores the frame-ancestors value in the content-security-policy header (and apparently, everything else but, "sandbox"). This means we can temporarily use Internet Explorer to display the page that contains our mashup. I looks like Edge is incorporating more and more values, though, so future versions of Microsoft browsers may not allow this workaround.

What I've Tried

I looked around for Tomcat filters that can configure the content-security-policy header. The HTTPSecurityHeaderFilter we use to configure the x-frame-options header doesn't appear to have any control over the content-security-policy header. There are third-party libraries out there that modify the header, but installing an extra library next to ThingWorx is not a best practice. Frameworks like Spring give you tools for configuring that header, but I can't go that deep into the stack.

I've looked and looked for a way to manipulate that header, but am coming up short. Any help setting the value of that header is appreciated.

10 REPLIES 10
sharmon
12-Amethyst
(To:sharmon)

It appears the help page has been updated over the last couple of days. I'm modifying my web.xml to include a filter like the following example:

<filter>

<filter-name>ClickjackFilterWhiteList</filter-name>

<filter-class>com.thingworx.security.filter.ClickjackFilter</filter-class>

<init-param>

<param-name>mode</param-name>

<param-value>WHITELIST</param-value>

</init-param>

<init-param>

<param-name>domains</param-name>

<param-value>http://media-pc:8080

http://192.168.152.133:8080 http://domainY.com</param-value>

</init-param>

</filter>


I am still having trouble with my CLASSPATH. My installation of Tomcat cannot find com.thingworx.security.filter.ClickjackFilter on startup, so I get, "Filter failed to load messages." I'll be working on getting that class on my class path tomorrow. It's reputed to live in ${CATALINA_HOME}/webapps/ThingWorx/WEB-INF//lib/thingworx-platform-common-8.0.2-b67.jar.

sharmon
12-Amethyst
(To:sharmon)

Working through this issue, step-by-step. We were getting the following error:

Cant  find Class Click Jack Filter - Message (HTML).png

For search-ability's sake, that's, "java.lang.ClassNotFoundException: com.thingworx.security.filter.ClickjackFilter.

We fixed that issue by doing the following (Ubuntu 14.x):

  • Created setenv.sh in ${CATALINA_HOME}/bin.
  • Made changed owner of setenv.sh to tomcat8.5 (account running Tomcat) and made the same executable by user tomcat8.5.
  • Entered the following line in setenv.sh:
    • export CLASSPATH=${CATALINA_HOME}/webapps/Thingworx/WEB-INF/lib/thingworx-platform-common-8.0.2-b67.jar

These steps fixed the problem with the ClickjackFilter class. We started getting the following exception, however:

Javax-Servlet-Filter-Error.png

Presumably, javax.servlet.filter is in the class hierarchy of ClickjackFilter. We'll add to the classpath, and update this topic when we're done.

sharmon
12-Amethyst
(To:sharmon)

BTW - this is the classpath we're using when Tomcat starts up:

Using CLASSPATH:      /opt/tomcat8.5/8.5.13/webapps/Thingworx/WEB-INF/lib/thingworx-platform-common-8.0.2-b67.jar:/opt/tomcat8.5/8.5.13/bin/bootstrap.jar:/opt/tomcat8.5/8.5.13/bin/tomcat-juli.jar


The thingworx-platform-common-8.0.2-b67.jar is the one we added to the CLASSPATH using setenv.sh. That's the jar that contains com.thingworx.security.filter.ClickjackFilter. The rest of the classpath is created by catalina.sh as Tomcat starts up.


This problem ​can be ​caused by a conflicting/old version of servlet.jar being on the CLASSPATH. That's the current line of inquiry we are pursuing.

sharmon
12-Amethyst
(To:sharmon)

We're just walking the class hierarchy, at this point. Now it's org.slf4j.Logger.

sharmon
12-Amethyst
(To:sharmon)

Pro tip - edit the correct web.xml file. You may make the mistake I made, and edit the web.xml file in ${CATALINA_HOME}/conf.. You're going to want to edit the one in $CATALINA_HOME}/webapps/Thingworx/WEB-INF/, instead.

If you do that, you can forget about having to set CLASSPATHs to the Thingworx libraries, too. Stand by for a thorough write-up of the solution to this issue.

sharmon
12-Amethyst
(To:sharmon)

Using Click Jack Filters to Allow Mashups to be Displayed in an iFrame

ThingWorx's web.xml File

To make the header changes described in the original question, start by editing ${CATALINA_HOME}/webapps/Thingworx/WEB-INF/web.xml. If you're on a Linux server, you'll have to do a, "sudo su," to get the permissions you'll need to get there.

Make a backup of your original web.xml by copying it to something like, "web-original.xml." Open web.xml in the text editor of your choice. Like the (new) documentation says, you'll find three filters that deal with clickjacking, and three filter mappings that control them. The filters are, "turned on and off," with the filter mappings. Let's deal with the default behavior, first:

ClickjackFilterSameOrigin

Filter:

<filter>

  <filter-name>ClickjackFilterSameOrigin</filter-name>

  <filter-class>com.thingworx.security.filter.ClickjackFilter</filter-class>

  <init-param>

    <param-name>mode</param-name>

    <param-value>SAMEORIGIN</param-value>

  </init-param>

</filter>

  

Filter mapping:

<filter-mapping>

    <filter-name>ClickjackFilterSameOrigin</filter-name>

    <url-pattern>/*</url-pattern>

</filter-mapping>

  

The important thing with the filter is what comes back in the content-security-policy header. When I make a GET request for a mashup with the default settings, the header comes back as:



content-security-policy →frame-ancestors 'self'


In Chrome and Firefox, this means you're not going to be able to display your mashup in an iFrame. The current version of Internet Explorer (11.0.44) ignores the header, and will display an iFrame, but you can't depend upon that behavior staying the same.

ClickjackFilterDeny

ClickjackFilterDeny will prevent ​any ​type of framing to enable it, comment out the ClickjackFilterSameOrigin filter-mapping with <!-- ... -->, and un-comment the ClickjackFilterDeny filter-mapping. You don't have to comment out the filter; the filter mapping is what makes it take effect. Here's the filter:

<filter>

  <filter-name>ClickjackFilterDeny</filter-name>

  <filter-class>com.thingworx.security.filter.ClickjackFilter</filter-class>

  <init-param>

    <param-name>mode</param-name>

    <param-value>DENY</param-value>

  </init-param>

</filter>

 

Here's the filter mapping:

<!-- use the Deny version to exclude all framing -->

<filter-mapping>

  <filter-name>ClickjackFilterDeny</filter-name>

  <url-pattern>/*</url-pattern>

</filter-mapping>

 

When I make my GET request for a header, this is what comes back:

content-security-policy →frame-ancestors 'none'

ClickjackFilterWhiteList

Filter:

  <filter>

    <filter-name>ClickjackFilterWhiteList</filter-name>

    <filter-class>com.thingworx.security.filter.ClickjackFilter</filter-class>

    <init-param>

      <param-name>mode</param-name>

      <param-value>WHITELIST</param-value>

    </init-param>

    <init-param>

      <param-name>domains</param-name>

      <param-value>http://example.com https://foo.com https://greatERPsystem.com</param-value>

    </init-param>

  </filter>

 

Filter mapping:

  <!-- use the WhiteList version to allow framing from specified domains -->

  <filter-mapping>

    <filter-name>ClickjackFilterWhiteList</filter-name>

    <url-pattern>/*</url-pattern>

  </filter-mapping>

 

You list the domains where you'd like to allow ThingWorx mashups to be framed as a space-delimited list. Where I make my GET request, here's what I get:

content-security-policy →frame-ancestors 'self'

That's a, "fail." I'm expecting frame-ancestors http://example.com https://foo.com and https://greatERPsystem.com with that filter. I'll edit and update this answer after I've done more research.

Hi Stephan,

I tested this filter sometime back (maybe in 7.4) in a Windchill context (as per "Adding a ThingWorx Mashup to Windchill -  ThingWorx ClickJack Support") and it was working fine.

Are you sure you have only one Click Jack Filters configured at a time ?

Also can you confirm your version of ThingWorx ?

Thanks.

Also maybe try to increase the verbosity of the Security logger to ALL and check the SecurityLog.log for warning or errors.

sharmon
12-Amethyst
(To:smainente)

Stephane Mainente - I have a support case open now where I methodically step through the clickjack filters available in ThingWorx 8.x. Thanks for the tip on increasing verbosity on the security loggers. That should help me get more of the messages that com.thingworx.security.filters.ClickjackfilterWhiteList creates.

smanley
13-Aquamarine
(To:sharmon)

I was working with this a bit in ThingWorx 8.2 and noticed that the only way I can display a mashup in an iFrame is to remove all clickjack filter mappings. Using the whitelist, I continue to see the frame ancestors set to self, but if I comment it out, the mashup will display. The same does not work in 7.4 though. 

Announcements


Top Tags