You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@shindig.apache.org by "Mike Pawlowski (JIRA)" <ji...@apache.org> on 2013/08/14 00:00:48 UTC
[jira] [Updated] (SHINDIG-1927) JSON RPC servlet does not support
CORS properly
[ https://issues.apache.org/jira/browse/SHINDIG-1927?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Mike Pawlowski updated SHINDIG-1927:
------------------------------------
Description:
----------------------------------------------------------------------------------------
Problem
----------------------------------------------------------------------------------------
* Like other customers, we have the following requirement: Shindig running on different domain than container REVISITED
=> http://markmail.org/message/qqfnyjg6dfunfw3h
* JSON RPC servlet does not support CORS properly.
=> org.apache.shindig.protocol.JsonRpcServlet
=> Causes cross-domain XHRs to get gadget metadata to fail
- Servlet does not handle OPTIONS preflight requests, so CORS requests automatically fail
- http://www.html5rocks.com/static/images/cors_server_flowchart.png
* However, the RPC servlet does specify the "Access-Control-Allow-Origin" header
=> This interferes with Jetty / Tomcat CORS servlet filters and causes the actual POST request to fail
=> Cause: "If the response includes zero or more than one Access-Control-Allow-Origin header values, return fail and terminate this algorithm."
- http://www.w3.org/TR/cors/#resource-sharing-check
- The servlet filter is already providing a value for the "Access-Control-Allow-Origin" header downstream
----------------------------------------------------------------------------------------
Patch
----------------------------------------------------------------------------------------
Since, the CORS support is incomplete and does not work out-of-the-box, it is probably safer to just remove the CORS specific header setting in the RPC servlet altogether
i.e. HttpUtil.setCORSheader(servletResponse, containerConfig.<String>getList(token.getContainer(), "gadgets.parentOrigins"));
Will attach patch.
----------------------------------------------------------------------------------------
Background Information
----------------------------------------------------------------------------------------
* Shindig does not have out-of-the-box (OOTB) support for OpenSocial gadget containers hosted from one domain and the OpenSocial gadget renderer hosted from another domain
=> e.g.
- Examples application (OS gadget container): http://localhost:9081/examples/gadgets
- Shindig application (OS gadget renderer): http://localhost:9082/rpc, http://localhost:9082/gadgets/ifr, etc.
=> Deploying Shindig as a separate application in the Jazz Platform ecosystem is advantageous
- Prevents the requirement for each application that hosts OpenSocial gadgets to serve it's own local copy of Shindig
- Facilitates the sandboxing / compartmentalization / segregation of Shindig binaries from Jazz Platform related binaries
* Only the request to get gadget metadata needs to be executed via a cross-domain XHR
=> Executed by common container API (osapi.container) outside of the yet-to-be constructed gadget iframe before making a request to render the gadget iframe (needs gadget metadata to render the gadget)
* Possible solutions to fix the cross-domain XHR from the OS gadget container to OS gadget renderer to get the gadget metadata
=> (1) Use a transparent proxy on the gadget container server to proxy the metadata request to Shindig
- Complicates server configuration & deployment
- Causes support issues for customers with custom server setups (e.g. proxies, firewalls)
=> (2) Use HTML5 Cross-Origin Resource Sharing (CORS) support
- http://www.w3.org/TR/cors/
=> (3) Use JSONP
- http://www.ibm.com/developerworks/library/wa-aj-jsonp1/
- Only supports GET HTTP requests
- RPC servlet relies on POST HTTP requests
=> (4) Request metadata from server-side JSP and inline the JSON response in the gadget container page response
- Not dynamic. Cannot add a gadget to the container on-the-fly via AJAX (i.e. without a full page reload)
=> (5) Use a hidden iframe source from the Shindig server on the gadget container page to get the gadget metadata
- Need to define a special document on the Shindig server to fetch the gadget metadata and communicate back to the parent container via HTML5 postMessage API
=> (6) Inject custom JavaScript into the gadget iframe (when constructed) to get the gadget metadata
- "Chicken & the egg problem". Need the gadget metadata in order to render the gadget iframe
- Too hacky. Need to interfere with the internal workings & flow of control of the common container
----------------------------------------------------------------------------------------
Selected Solution (CORS)
----------------------------------------------------------------------------------------
* Decided to implement option (2) CORS approach
=> Use common container preloadGadget API to fetch the gadget metadata and force Shindig to cache the response
- http://opensocial-resources.googlecode.com/svn/spec/2.5/Core-Container.xml#osapi.container.Container.preloadGadget
=> Use common container navigateGadget API to render the gadget (e.g. Create iframe, etc.) using cached gadget metadata
- http://opensocial-resources.googlecode.com/svn/spec/2.5/Core-Container.xml#osapi.container.Container.navigateGadget
- Note: If preloadGadget call is omitted, then the navigateGadget call will try to fetch the gadget metadata itself and fail due to cross-domain security failures
* On Jetty, use built-in Cross Origin Filter feature
http://download.eclipse.org/jetty/7.6.11.v20130520/apidocs/org/eclipse/jetty/servlets/CrossOriginFilter.html
http://wiki.eclipse.org/Jetty/Feature/Cross_Origin_Filter
* On Tomcat, use built-in CORS filter feature
http://tomcat.apache.org/tomcat-7.0-doc/config/filter.html#CORS_Filter
----------------------------------------------------------------------------------------
Jetty Cross Origin Filter Configuration
----------------------------------------------------------------------------------------
<filter>
<filter-name>cross-origin</filter-name>
<filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
<init-param>
<param-name>allowedOrigins</param-name>
<param-value>*</param-value>
</init-param>
<init-param>
<param-name>allowedMethods</param-name>
<param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
</init-param>
<init-param>
<param-name>allowedHeaders</param-name>
<param-value>Content-Type,X-Requested-With,Accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
</init-param>
<init-param>
<param-name>preflightMaxAge</param-name>
<param-value>1800</param-value>
</init-param>
<init-param>
<param-name>allowCredentials</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>chainPreflight</param-name>
<param-value>false</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>cross-origin</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
----------------------------------------------------------------------------------------
Tomcat CORS Filter Configuration
----------------------------------------------------------------------------------------
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
<init-param>
<param-name>cors.allowed.origins</param-name>
<param-value>*</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.methods</param-name>
<param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.headers</param-name>
<param-value>Content-Type,X-Requested-With,Accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
</init-param>
<init-param>
<param-name>cors.support.credentials</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>cors.preflight.maxage</param-name>
<param-value>1800</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
was:
----------------------------------------------------------------------------------------
Problem
----------------------------------------------------------------------------------------
* Like other customers, we have the following requirement: Shindig running on different domain than container REVISITED
=> http://markmail.org/message/qqfnyjg6dfunfw3h
* JSON RPC servlet does not support CORS properly.
=> org.apache.shindig.protocol.JsonRpcServlet
=> Causes cross-domain XHRs to get gadget metadata to fail
- Servlet does not handle OPTIONS preflight requests, so CORS requests automatically fail
* However, the RPC servlet does specify the "Access-Control-Allow-Origin" header
=> This interferes with Jetty / Tomcat CORS servlet filters and causes the actual POST request to fail
=> Cause: "If the response includes zero or more than one Access-Control-Allow-Origin header values, return fail and terminate this algorithm."
- http://www.w3.org/TR/cors/#resource-sharing-check
- The servlet filter is already providing a value for the "Access-Control-Allow-Origin" header downstream
----------------------------------------------------------------------------------------
Patch
----------------------------------------------------------------------------------------
Since, the CORS support is incomplete and does not work out-of-the-box, it is probably safer to just remove the CORS specific header setting in the RPC servlet altogether
i.e. HttpUtil.setCORSheader(servletResponse, containerConfig.<String>getList(token.getContainer(), "gadgets.parentOrigins"));
Will attach patch.
----------------------------------------------------------------------------------------
Background Information
----------------------------------------------------------------------------------------
* Shindig does not have out-of-the-box (OOTB) support for OpenSocial gadget containers hosted from one domain and the OpenSocial gadget renderer hosted from another domain
=> e.g.
- Examples application (OS gadget container): http://localhost:9081/examples/gadgets
- Shindig application (OS gadget renderer): http://localhost:9082/rpc, http://localhost:9082/gadgets/ifr, etc.
=> Deploying Shindig as a separate application in the Jazz Platform ecosystem is advantageous
- Prevents the requirement for each application that hosts OpenSocial gadgets to serve it's own local copy of Shindig
- Facilitates the sandboxing / compartmentalization / segregation of Shindig binaries from Jazz Platform related binaries
* Only the request to get gadget metadata needs to be executed via a cross-domain XHR
=> Executed by common container API (osapi.container) outside of the yet-to-be constructed gadget iframe before making a request to render the gadget iframe (needs gadget metadata to render the gadget)
* Possible solutions to fix the cross-domain XHR from the OS gadget container to OS gadget renderer to get the gadget metadata
=> (1) Use a transparent proxy on the gadget container server to proxy the metadata request to Shindig
- Complicates server configuration & deployment
- Causes support issues for customers with custom server setups (e.g. proxies, firewalls)
=> (2) Use HTML5 Cross-Origin Resource Sharing (CORS) support
- http://www.w3.org/TR/cors/
=> (3) Use JSONP
- http://www.ibm.com/developerworks/library/wa-aj-jsonp1/
- Only supports GET HTTP requests
- RPC servlet relies on POST HTTP requests
=> (4) Request metadata from server-side JSP and inline the JSON response in the gadget container page response
- Not dynamic. Cannot add a gadget to the container on-the-fly via AJAX (i.e. without a full page reload)
=> (5) Use a hidden iframe source from the Shindig server on the gadget container page to get the gadget metadata
- Need to define a special document on the Shindig server to fetch the gadget metadata and communicate back to the parent container via HTML5 postMessage API
=> (6) Inject custom JavaScript into the gadget iframe (when constructed) to get the gadget metadata
- "Chicken & the egg problem". Need the gadget metadata in order to render the gadget iframe
- Too hacky. Need to interfere with the internal workings & flow of control of the common container
----------------------------------------------------------------------------------------
Selected Solution (CORS)
----------------------------------------------------------------------------------------
* Decided to implement option (2) CORS approach
=> Use common container preloadGadget API to fetch the gadget metadata and force Shindig to cache the response
- http://opensocial-resources.googlecode.com/svn/spec/2.5/Core-Container.xml#osapi.container.Container.preloadGadget
=> Use common container navigateGadget API to render the gadget (e.g. Create iframe, etc.) using cached gadget metadata
- http://opensocial-resources.googlecode.com/svn/spec/2.5/Core-Container.xml#osapi.container.Container.navigateGadget
- Note: If preloadGadget call is omitted, then the navigateGadget call will try to fetch the gadget metadata itself and fail due to cross-domain security failures
* On Jetty, use built-in Cross Origin Filter feature
http://download.eclipse.org/jetty/7.6.11.v20130520/apidocs/org/eclipse/jetty/servlets/CrossOriginFilter.html
http://wiki.eclipse.org/Jetty/Feature/Cross_Origin_Filter
* On Tomcat, use built-in CORS filter feature
http://tomcat.apache.org/tomcat-7.0-doc/config/filter.html#CORS_Filter
----------------------------------------------------------------------------------------
Jetty Cross Origin Filter Configuration
----------------------------------------------------------------------------------------
<filter>
<filter-name>cross-origin</filter-name>
<filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
<init-param>
<param-name>allowedOrigins</param-name>
<param-value>*</param-value>
</init-param>
<init-param>
<param-name>allowedMethods</param-name>
<param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
</init-param>
<init-param>
<param-name>allowedHeaders</param-name>
<param-value>Content-Type,X-Requested-With,Accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
</init-param>
<init-param>
<param-name>preflightMaxAge</param-name>
<param-value>1800</param-value>
</init-param>
<init-param>
<param-name>allowCredentials</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>chainPreflight</param-name>
<param-value>false</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>cross-origin</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
----------------------------------------------------------------------------------------
Tomcat CORS Filter Configuration
----------------------------------------------------------------------------------------
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
<init-param>
<param-name>cors.allowed.origins</param-name>
<param-value>*</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.methods</param-name>
<param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.headers</param-name>
<param-value>Content-Type,X-Requested-With,Accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
</init-param>
<init-param>
<param-name>cors.support.credentials</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>cors.preflight.maxage</param-name>
<param-value>1800</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
> JSON RPC servlet does not support CORS properly
> -----------------------------------------------
>
> Key: SHINDIG-1927
> URL: https://issues.apache.org/jira/browse/SHINDIG-1927
> Project: Shindig
> Issue Type: Bug
> Components: Java
> Affects Versions: 2.5.0
> Environment: * Jetty 9.0.3.v20130506
> * Apache Tomcat 7.0.42 (64-bit)
> Reporter: Mike Pawlowski
> Priority: Minor
>
> ----------------------------------------------------------------------------------------
> Problem
> ----------------------------------------------------------------------------------------
> * Like other customers, we have the following requirement: Shindig running on different domain than container REVISITED
> => http://markmail.org/message/qqfnyjg6dfunfw3h
> * JSON RPC servlet does not support CORS properly.
> => org.apache.shindig.protocol.JsonRpcServlet
> => Causes cross-domain XHRs to get gadget metadata to fail
> - Servlet does not handle OPTIONS preflight requests, so CORS requests automatically fail
> - http://www.html5rocks.com/static/images/cors_server_flowchart.png
>
> * However, the RPC servlet does specify the "Access-Control-Allow-Origin" header
> => This interferes with Jetty / Tomcat CORS servlet filters and causes the actual POST request to fail
> => Cause: "If the response includes zero or more than one Access-Control-Allow-Origin header values, return fail and terminate this algorithm."
> - http://www.w3.org/TR/cors/#resource-sharing-check
> - The servlet filter is already providing a value for the "Access-Control-Allow-Origin" header downstream
>
> ----------------------------------------------------------------------------------------
> Patch
> ----------------------------------------------------------------------------------------
> Since, the CORS support is incomplete and does not work out-of-the-box, it is probably safer to just remove the CORS specific header setting in the RPC servlet altogether
> i.e. HttpUtil.setCORSheader(servletResponse, containerConfig.<String>getList(token.getContainer(), "gadgets.parentOrigins"));
> Will attach patch.
>
> ----------------------------------------------------------------------------------------
> Background Information
> ----------------------------------------------------------------------------------------
> * Shindig does not have out-of-the-box (OOTB) support for OpenSocial gadget containers hosted from one domain and the OpenSocial gadget renderer hosted from another domain
> => e.g.
> - Examples application (OS gadget container): http://localhost:9081/examples/gadgets
> - Shindig application (OS gadget renderer): http://localhost:9082/rpc, http://localhost:9082/gadgets/ifr, etc.
> => Deploying Shindig as a separate application in the Jazz Platform ecosystem is advantageous
> - Prevents the requirement for each application that hosts OpenSocial gadgets to serve it's own local copy of Shindig
> - Facilitates the sandboxing / compartmentalization / segregation of Shindig binaries from Jazz Platform related binaries
> * Only the request to get gadget metadata needs to be executed via a cross-domain XHR
> => Executed by common container API (osapi.container) outside of the yet-to-be constructed gadget iframe before making a request to render the gadget iframe (needs gadget metadata to render the gadget)
>
> * Possible solutions to fix the cross-domain XHR from the OS gadget container to OS gadget renderer to get the gadget metadata
> => (1) Use a transparent proxy on the gadget container server to proxy the metadata request to Shindig
> - Complicates server configuration & deployment
> - Causes support issues for customers with custom server setups (e.g. proxies, firewalls)
> => (2) Use HTML5 Cross-Origin Resource Sharing (CORS) support
> - http://www.w3.org/TR/cors/
> => (3) Use JSONP
> - http://www.ibm.com/developerworks/library/wa-aj-jsonp1/
> - Only supports GET HTTP requests
> - RPC servlet relies on POST HTTP requests
> => (4) Request metadata from server-side JSP and inline the JSON response in the gadget container page response
> - Not dynamic. Cannot add a gadget to the container on-the-fly via AJAX (i.e. without a full page reload)
> => (5) Use a hidden iframe source from the Shindig server on the gadget container page to get the gadget metadata
> - Need to define a special document on the Shindig server to fetch the gadget metadata and communicate back to the parent container via HTML5 postMessage API
> => (6) Inject custom JavaScript into the gadget iframe (when constructed) to get the gadget metadata
> - "Chicken & the egg problem". Need the gadget metadata in order to render the gadget iframe
> - Too hacky. Need to interfere with the internal workings & flow of control of the common container
> ----------------------------------------------------------------------------------------
> Selected Solution (CORS)
> ----------------------------------------------------------------------------------------
> * Decided to implement option (2) CORS approach
> => Use common container preloadGadget API to fetch the gadget metadata and force Shindig to cache the response
> - http://opensocial-resources.googlecode.com/svn/spec/2.5/Core-Container.xml#osapi.container.Container.preloadGadget
> => Use common container navigateGadget API to render the gadget (e.g. Create iframe, etc.) using cached gadget metadata
> - http://opensocial-resources.googlecode.com/svn/spec/2.5/Core-Container.xml#osapi.container.Container.navigateGadget
> - Note: If preloadGadget call is omitted, then the navigateGadget call will try to fetch the gadget metadata itself and fail due to cross-domain security failures
> * On Jetty, use built-in Cross Origin Filter feature
> http://download.eclipse.org/jetty/7.6.11.v20130520/apidocs/org/eclipse/jetty/servlets/CrossOriginFilter.html
> http://wiki.eclipse.org/Jetty/Feature/Cross_Origin_Filter
> * On Tomcat, use built-in CORS filter feature
> http://tomcat.apache.org/tomcat-7.0-doc/config/filter.html#CORS_Filter
> ----------------------------------------------------------------------------------------
> Jetty Cross Origin Filter Configuration
> ----------------------------------------------------------------------------------------
> <filter>
> <filter-name>cross-origin</filter-name>
> <filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
> <init-param>
> <param-name>allowedOrigins</param-name>
> <param-value>*</param-value>
> </init-param>
> <init-param>
> <param-name>allowedMethods</param-name>
> <param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
> </init-param>
> <init-param>
> <param-name>allowedHeaders</param-name>
> <param-value>Content-Type,X-Requested-With,Accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
> </init-param>
> <init-param>
> <param-name>preflightMaxAge</param-name>
> <param-value>1800</param-value>
> </init-param>
> <init-param>
> <param-name>allowCredentials</param-name>
> <param-value>true</param-value>
> </init-param>
> <init-param>
> <param-name>chainPreflight</param-name>
> <param-value>false</param-value>
> </init-param>
> </filter>
> <filter-mapping>
> <filter-name>cross-origin</filter-name>
> <url-pattern>/*</url-pattern>
> </filter-mapping>
> ----------------------------------------------------------------------------------------
> Tomcat CORS Filter Configuration
> ----------------------------------------------------------------------------------------
> <filter>
> <filter-name>CorsFilter</filter-name>
> <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
> <init-param>
> <param-name>cors.allowed.origins</param-name>
> <param-value>*</param-value>
> </init-param>
> <init-param>
> <param-name>cors.allowed.methods</param-name>
> <param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
> </init-param>
> <init-param>
> <param-name>cors.allowed.headers</param-name>
> <param-value>Content-Type,X-Requested-With,Accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
> </init-param>
> <init-param>
> <param-name>cors.support.credentials</param-name>
> <param-value>true</param-value>
> </init-param>
> <init-param>
> <param-name>cors.preflight.maxage</param-name>
> <param-value>1800</param-value>
> </init-param>
> </filter>
> <filter-mapping>
> <filter-name>CorsFilter</filter-name>
> <url-pattern>/*</url-pattern>
> </filter-mapping>
--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira