Skip to content

Using HTTPS and WebAPI

Ioannis Charalampidis edited this page Nov 22, 2015 · 5 revisions

Since the CernVM WebAPI daemon runs an HTTP server, bound to the localhost address it's not possible to use SSL encryption. That's because it's not possible to issue an SSL certificate for the localhost address, and installing our own CA in user's computer implies additional security risks.

Unfortunately, due to the latest HTML5 security policies, that restrict the mixing of HTTP and HTTPS content, the javascript library cannot establish a websocket connection to the WebAPI Daemon if it's served under HTTPS.

There is a simple solution to this problem, but it only works if you do not need to have real-time feedback to the hosting website:

  1. Prepare your VMCP response while in the secure session
  2. Store it under a key with unique ID and
  3. open an HTTP pop-up window to handle the request.

You can read more in the next section:

Popping-up an Insecure "Launch" Window

As mentioned before, the easiest trick is to compile the configuration of your VM while in a secure session and open an insecure pop-up window to handle the launching process. Let's explore this option in a step-by-step example:

Step 1 - Compile the VMCP Configuration

Let's say that the user is in your website https://website.com/repository and picks to start a particular VM. Since we are using SSL, we cannot use WebAPI, but we can still open a pop-up window under http:. Therefore we are focusing on creating a secure mechanism to deliver the required information from the https: version of the website to the http: version of the website.

Therefore, upon the start request, we can use the session information (ex. current user's name, preferences etc.) and the user's choice to compile the specifications of the VM we want to serve as a VMCP object:

{
    "name": "John__UbuntuVM",
    "secret": "us3rspassword",
    "vcpus": 1,
    "memory": 512,
    "cernvmVersion": "latest",
    "flags": 8,
    "userData": "[amiconfig]\nplugins=cernvm\n[cernvm]\nusers=user:users:usersecret",
}

Then create a cryptographically unique ID and store this object in a key/value store under this ID.

Let's say for our example that the ID is 4DC05982-614C-4539-8E0E-D2C4B37C6C92

Step 2 - Create an Insecure VMCP Response URL

In order to pass these data to CernVM WebAPI you will need a VMCP endpoint. Since we are going to serve it under an HTTP session you will need to expose these information under a dedicated URL. This URL will be composed of a fixed prefix and the unique ID generated in the previous step. For example: http://website.com/vmcp/4DC05982-614C-4539-8E0E-D2C4B37C6C92

For improved user experience it's a good idea to have this URL completely exposed to the public, session-less, without any restriction. The data are protected since the ID is unique. As an additional security measure, you should delete the key after the URL is accessed once.

This URL should properly respond with a signed VMCP response according to the guidelines found in the Calculating VMCP Signature page.

Step 3 - Serve a Simple WebAPI Launcher Under a Parametric URL

Having your VMCP endpoint available under an insecure URL you can now safely host the rest of your WebAPI javascript code in a separate URL, served under http. Upon visiting the URL, the VM should be immediately launched.

This way, we have a URL in the following form: http://website.com/launch?id=4DC05982-614C-4539-8E0E-D2C4B37C6C92 that upon visiting will immediately start the VM.

As a reference, you can check the javascript function we are using in CernVM Online:

	/**
	 * Launch a VM using the specified VMCP URL 
	 */
	window.launchMachine = function(vmcp_url) {

		// Initialize CernVM WebAPI
		CVM.startCVMWebAPI(function(api) {
			$("#lbl-status").text("CernVM WebAPI Ready");

			// Bind progress listeners on the plugin instance
			api.addEventListener('started', progress_started);
			api.addEventListener('completed', progress_completed);
			api.addEventListener('progress', progress_updated);
			api.addEventListener('failed', progress_error);
			api.addEventListener('disconnected', disconnected);

			// Request a session through our specified VMCP endpoint
			api.requestSession(vmcp_url, function(session) {
				$("#lbl-status").text("Session open");
										
				// Bind progress listeners on the session instance
				session.addEventListener('started', progress_started);
				session.addEventListener('completed', progress_completed);
				session.addEventListener('progress', progress_updated);
				session.addEventListener('failed', progress_error);

				// Listen for state changed events
				session.addEventListener('stateChanged', function(newState) {
					// When we are running we don't need the window any more
					if (newState == 5) {
						window.close();
					}
				});

				// We just start the session the moment we get it
				session.start();

			});

		});

	}

We are passing the VM ID from the GET parameter as a first argument to the javascript function. Again the following snipped is from CernVM Online:

        <script type="text/javascript">launchMachine('{{vmcp}}');</script>

Step 4 - Coming back to HTTPS

Now that we have all of our components in place, we can create a pop-up window to handle user's request in the following steps:

  1. When clicking Start, open a pop-up window, pointing to an https 'bootstrap' url.
  2. Compile the VMCP data seen in Step 1.
  3. Redirect to the HTTP URL of Step 3.
  4. Upon successful launch, close the pop-up window.

You can see in CernVM Online how we are opening the bootstrap URL. Be aware that you need to allocate enough space for the in-page pop-up windows to be visible. 700x500 pixels is a good starting point.

Example

As an example, you can see the webapi application in the CernVM Online django app : https://github.com/cernvm/cernvm-online/tree/master/src/cvmo/webapi