March 1, 2022
For anyone who has ever encountered the Access to XMLHttpRequest at 'http://my-maximo.com' from origin at 'http://my-web-app.com' has been blocked by CORS policy: Response preflight request doesn't pass access control check
error, this post is for you.
This error is the result of the Same-Origin security Policy (SOP), which by default prevents a script request from one origin from accessing resources in another origin. In the example error message, http://my-web-app.com is one origin and has a script attempting to access http://my-maximo.com, a second origin.
The SOP policy is designed to prevent malicious scripts from one origin accessing information on another origin through the document object model (DOM). This only applies to scripts, and not other resources such as images, css or other resources.
For an excellent overview and reference on CORS, see the Mozilla Developer Network (MDN) entry here: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
With later versions of Maximo providing a rich REST API, the opportunity to access and consume Maximo data from external web applications becomes possible, but quickly runs into challenges with the same-origin policy if the external application is hosted outside the Maximo host. Fortunately there is a Cross-Origin Resource Sharing (CORS) policy, which allows a server to allow other origins to access otherwise secured resources.
This only applies to browser based applications accessing the Maximo REST API, so for many, this will never apply. However, for those who run into Same-Origin and CORS errors, the following will provide a guide to properly configure your Maximo environment for access from external web applications.
As previously mentioned, CORS policies allows a server (in our case Maximo), to specify other origins that are allowed to load resources from it. This includes the details of the resources that can be accessed, and the HTTP mechanisms that allowed to be used as part of this access.
As CORS policies are defined in the HTTP response headers, there are multiple approaches for configuring a Maximo environment to return the desired CORS headers. In this post we are going to cover three different approaches: one for the traditional IBM HTTP Server (IHS) with WebSphere Traditional, one for WebSphere Liberty Profile (WLP) and one native to Maximo.
The table below lists the CORS-related HTTP headers with a description of how they impact behavior.
Header | Description |
---|---|
Access-Control-Allow-Credentials | The only valid value is true (case sensitive) and indicates that credentials such as authorization headers may be shared. |
Access-Control-Allow-Origin | The origin allowed by the server. This may contain the * wildcard character. |
Access-Control-Allow-Methods | The HTTP methods allowed: DELETE, GET, OPTIONS, PATCH, POST, PUT. Note that Maximo does not support PATCH. |
Access-Control-Allow-Headers | The HTTP headers allowed in a CORS request. This may include common headers such as Content-Type . |
Access-Control-Expose-Headers | The HTTP response headers that are available to the external origin script. |
Access-Control-Max-Age | The maximum age in seconds of the initial preflight CORS access check prior to the request being made. |
Note that for the
Access-Control-Allow-Origin
header additional security protocol restrictions apply, such that ahttp
protocol origin cannot access ahttps
resource.
Per our example, to allow our external web application at https://my-web-app.com to have general access to the Maximo REST API, we want to configure our Maximo environment to return the following headers:
Header | Value |
---|---|
Access-Control-Allow-Credentials | true |
Access-Control-Allow-Origin | https://my-web-app.com |
Access-Control-Allow-Methods | POST, GET, HEAD, PUT, OPTIONS |
Access-Control-Allow-Headers | authorization, content-type, maxauth, x-public-uri |
Access-Control-Expose-Headers | csrftoken |
Access-Control-Max-Age | 3600 |
The IBM HTTP Server (IHS) is the standard web server for accessing Maximo that is deployed in the WebSphere Application Server (WAS) Traditional application server. If you see this login screen when you deploy your Maximo EAR file, you are using WebSphere Traditional.
The IHS is a branch of the Apache Web Server and long predates CORS, so there is no specific support for specifying CORS policies. Fortunately there is the mod_headers
module that allows headers to be dynamically injected by the server and this module is provided by default with the IHS.
Full documentation for the
mod_headers
can be found here https://httpd.apache.org/docs/current/mod/mod_headers.html
To add mod_headers
support simply use the LoadModule
directive with the name of the module and path to the .so
(Linux) or .dll
(Windows) library. This will load the Header
directive which can then be used with the set
action to add headers to each response. The following example can be added to the $IHS_ROOT/conf/httpd.conf
file where $IHS_ROOT
is the installation folder for IHS.
LoadModule headers_module modules/mod_headers.soHeader set Access-Control-Allow-Credentials trueHeader set Access-Control-Allow-Origin https://my-web-app.comHeader set Access-Control-Allow-Methods "POST, GET, HEAD, PUT, OPTIONS"Header set Access-Control-Allow-Headers "authorization, content-type, maxauth, x-public-uri"Header set Access-Control-Expose-Headers "csrftoken"Header set Access-Control-Max-Age 3600
I personally prefer to keep customizations and configurations to IHS in a separate file. I create a directory named
maximo
in the$IHS_ROOT/conf
directory and then add theInclude
directiveInclude conf/maximo/*.conf
at at the end of the$IHS_ROOT/conf/httpd.conf
file. I then place each configuration in its own.conf
file and they are dynamically included in the configuration, so I can easily identify, modify or remove configurations. For this example I would create a file named$IHS_HOME/conf/maximo/headers.conf
and place the above configuration in it.
Although not specifically CORS, the SameSite Set-Cookie attribute specifies when cookies will be sent to cross site domains. If you require cookies to be shared with cross site domains you must specify the SameSite Set-Cookie attribute as None
. This used to be the default value, but it has recently changed to default to Lax
, which only sends cookies when the user is navigating to the origin site. Full details of the SameSite
Set-Cookie attribute can be found here https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite.
Fortunately, IBM has provided a configuration file to allow the appropriate header response. Following the previous advice, you can download the same-site-global.conf
file from IBM and save it in the $IHS_HOME/conf/maximo/
directory.
http://publib.boulder.ibm.com/httpserv/ihsdiag/_static/samesite-global.conf
A support article from IBM is available here to understand how SameSite is handled by WebSphere and IHS. https://www.ibm.com/support/pages/browser-changes-samesite-cookie-handling-and-websphere-application-server
WebSphere Liberty Profile (WLP) is the new light weight version of WebSphere that includes composable features so you only need to load what is needed and not what is not. It became available for use in Maximo 7.6.0.9 and is the default (and only choice) for Maximo Application Suite.
WLP has built in CORS support that can be configured as part of the deployment server.xml
configuration. The configuration is very simple, add the <cors />
XML tag with the following attributes that correspond the the CORS headers. The previous example for IHS is re-implemented below.
<cors domain="maximo/oslc"allowCredentials="true"allowedOrigins="https://my-web-app.com"allowedMethods="POST, GET, HEAD, PUT, OPTIONS"allowedHeaders="authorization, content-type, maxauth, x-public-uri"exposeHeaders="csrftoken"maxAge="3600" />
WebSphere Liberty provides the <samesite />
XML tag that supports the lax
, strict
and none
attributes with each containing a comma separated list of cookie names for each policy or the wildcard character *
to indicate all cookies. The <samesite />
XML tag can be embedded within the <httpEndpoint />
tag or standalone with an id
attribute that can be referenced through the samesiteRef
attribute on the <httpEndpoint />
tag. An example of the configuration can be seen below.
<httpEndpoint id="defaultHttpEndpoint"httpPort="80"httpsPort="443" ><samesite lax="firstCookie,secondCookie" strict="strictCookie" none="all, other, cookies"/></httpEndpoint>
A full discussion of the `
https://openliberty.io/blog/2020/03/25/set-samesite-attribute-cookies-liberty.html
The previous examples not withstanding, Maximo provides CORS support directly without having to modify the application server configuration. The CORS headers can be added simply by setting the following Maximo System Properties. The table below provides the property name, description and the corresponding CORS header that it affects.
Property | Description | Affected Header |
---|---|---|
mxe.oslc.aclalloworigin | CORS http origin urls allowed. | Access-Control-Allow-Origin |
mxe.oslc.aclallowmethods | CORS http methods allowed. | Access-Control-Allow-Methods |
mxe.oslc.aclallowheaders | CORS http headers allowed. | Access-Control-Allow-Headers |
mxe.oslc.aclexposeheaders | CORS http response headers allowed. | Access-Control-Expose-Headers |
All you have to do is set these properties with the values previously discussed and your CORS headers will be properly set.
Maximo does not currently have support for setting the SameSite Set-Cookie attribute directly. If you need to modify the SameSite attribute of the Set-Cookie header you will need to apply it either in Apache or WebSever Liberty as discussed previous.
In this post we explored configuring the IBM HTTP Server, WebSphere Liberty Profile, and Maximo directly for Cross-Origin Resource Sharing. While the Maximo approach is by far the easiest and straight forward configuration, the other options are sometimes useful tools and are good for understanding how CORS works. As mentioned at the start of the post, CORS only affects applications running in a browser, so third party application, mobile solutions, and other utilities are not impacted by CORS.
If you have any questions or comments please reach out to us at [email protected]