Web browsers enforce something called the same origin policy to prevent malicious scripts from accessing sensitive data. This policy prevents a script running on one page from accessing data on a second page if the second page is not served using the same scheme, host and port as the first. Because of this, you previously could not call the Streams REST APIs directly from a script; rather, you needed an intermediate web application to retrieve information from the REST APIs and make it available to the script. With Streams 4.1, cross-origin resource sharing (CORS) support was added to the REST APIs providing a new, easier alternative. The CORS support allows for direct access from trusted scripts. With this solution, you use new configuration support to identify which requests to trust and Streams works with the browser to allow only these requests. In this article, I provide a sample script that makes cross-origin REST API requests and I take you through the steps to successfully run this script using the new CORS support.
The steps for making cross-origin REST API calls are as follows:
- Verify your browser supports CORS.
Most modern browsers have support for CORS; however, some browsers originally provided limited support and later provided a more complete solution. Therefore, it is best to ensure you are running the latest version of your CORS-supported browser. Some browsers impose additional restrictions on cross-origin requests beyond what is defined in the CORS specification. If you are having problems making cross-origin requests, try consulting your browser’s documentation or using a different browser.
- Ensure the Streams server certificate is trusted by the browser.
The browser will deny requests to servers for which it does not have a trusted certificate. Streams uses a self-signed certificate to identify itself. You can use the following streamtool command to retrieve this certificate:
Next, use your browser’s configuration support to import the certificate into the browser. If this step is skipped and you try to access the server from a script, the error you get from the browser often does not include details about the reason for the failure.
- Download the sample web page.
You can download the web page containing the sample script here. This sample prompts for a user, password, and a REST API to call. Upon pressing the button, it submits the cross-origin REST API request. It then displays the results (success or failure) at the bottom of the page.
- Use a web server to serve the sample page.
You can use any available web server to serve the sample page. An easy option for testing, if available, is to use the built-in Python HTTP server. To do this, you would run the following commands:
python -m SimpleHTTPServer 8085
where ~/myCorsSample is the path containing the sample web page and 8085 is an available port.
- Add the web server origin to the trusted origins list.
The web server origin is the scheme, host, and port used to serve the web page. Streams rejects any cross-origin request with an origin that is not in the trusted origins list. You can use either streamtool, the domain console, or JMX to add the origin to the trusted list. An example using streamtool is:
streamtool addtrustedorigin -d mydomain http://mywebserver:8085
where mydomain is the Streams domain and http://myweberserver:8085 is the origin to trust.
The origin must be an exact match to the value specified by the HTTP Origin header when the request is made. I will discuss how you can find this value later in the article. Sometimes there are multiple ways to specify the same origin. For example, if the default port is being used you typically would omit it when launching the page; however, explicitly including the port is also valid. Another example is the host. You could load the page using the host name or the IP address. You will need to add each of these you want to trust to the list.
- Make the cross-origin request.
Here is the relevant portion of the script used for making the cross-origin request. It is called when the button is pressed on the page.
var xhr = new XMLHttpRequest();
xhr.withCrendentials = true;
xhr.setRequestHeader(‘Authorization’,’Basic ‘ + btoa(user + ‘:’ + password));
Line 1: The XMLHttpRequest API is used for making the REST call.
Line 2: The withCredentials property must be set to true because Streams requires authentication.
Line 3: The HTTP GET method is called with the supplied REST URI.
Line 4: The user and password are set in the HTTP Authorization header.
Line 5: The request is sent.
If the cross-origin request does not succeed, you can use the browser’s debugger to help determine what went wrong. Debugger output is shown for some possible scenarios below.
- Server certificate not trusted by browser â€“ In this case the error is fairly generic and is basically saying the browser detected an issue and the request did not make it as far as the Streams REST server. You would also see this error if you specified an incorrect host or port on the REST URI.
- Origin not in trusted origins list â€“ This scenario returns the same generic error, but also includes a second message saying the Access-Control-Allow-Origin response header is missing. This happens if you do not add the origin to the trusted list or if you added it incorrectly.
The debugger used here also provides a way to view the HTTP request and response headers for the request. This is useful for verifying you added the correct origin value to the trusted list.
- Successful request with preflight â€“ In the successful case, there are no error messages and you can see two HTTP requests are made. The first is an OPTIONS request, followed by the GET request specified in the script. The CORS specification calls for a preflight OPTIONS request whenever the actual request contains more than just simple request headers. This preflight request must be authorized before the actual request is sent. In our example, we included the Authorization header so the OPTIONS request preceded the GET request. In this case, you can also see the Access-Control-Allow-Origin response header is now included.
Adding support for CORS to the REST APIs makes it much easier for you to access the REST APIs from scripts, while still providing the security of configuring which requests to trust. You can use the information in this article to gain access to Streams domain, instance, resource, and job information as well as to job metrics and view data from your own scripts.