Public access to your Cloud Files account#

This section describes ways that you can allow others to place objects into or retrieve objects from your Cloud Files account. With the methods described here, users do not need your password or login information to have access to your account.

TempURL#

You can use the Temporary URL feature (TempURL) to create limited-time Internet addresses that allow limited access to your Cloud Files account. Using TempURL, you can allow others to retrieve objects from or place objects in your Cloud Files account for a specified amount of time. After the specified amount of time expires, access to the account with the TempURL is denied.

Note

If the access time expires while a large file is being retrieved, the download continues until it is finished. Only the link expires.

Access to your Cloud Files account or website with a TempURL is independent of whether your account is CDN-enabled. Even if you do not CDN-enable a directory, you can still grant temporary public access through a TempURL. When you create a TempURL, Cloud Files validates a GET-accessible or PUT-accessible URL, which is time-limited.

Note

The TempURL is the same thing as the TempURL Secret, and is set using the TempURL metadata key described in the next section. The TempURL is the actual URL.

Set account TempURL metadata key#

To create a TempURL, you must first set the X-Account-Meta-Temp-Url-Key metadata header on your Cloud Files account to a key that only you know. This key can be any arbitrary sequence.

Note

Changing the X-Account-Meta-Temp-URL-Key invalidates any previously generated TempURLs within 60 seconds (the cache time for the key). To allow transitioning to a new key without effecting service, Cloud Files supports up to two keys, specified by X-Account-Meta-Temp-URL-Key and X-Account-Meta-Temp-URL-Key-2. Signatures are checked against both keys, if present. Testing both keys enables key rotation without invalidating all existing TempURLs — you can create TempURLs with a new key while allowing TempURLs created with the original key to remain valid. Once all the TempURLs generated with the old key have been exhausted, you can change or remove the old key.

Example: Set account metadata key for public access: HTTP request

POST /v1/MossoCloudFS_0672d7fa-9f85-4a81-a3ab-adb66a880123 HTTP/1.1
Host: storage.clouddrive.com
X-Auth-Token: f064c46a782c444cb4ba4b6434288f7c
X-Account-Meta-Temp-Url-Key: yourKey

Any class 200 status code indicates success.

Create the TempURL#

After the metadata is set, you must create an HMAC-SHA256 (RFC 2403) signature. When you generate the TempURL, you determine which method of access you will grant users, GET or PUT. You also determine the path to the object to which you are granting access. Lastly, you set the time for your TempURL to expire in UNIX epoch notation.

Note

You can also use HMAC-SHA1 (RFC 2104) with TempURL, but HMAC-SHA256 is stronger crytographically.

In the following examples, a TempURL that will be available for 60 seconds is generated for the my_cat.jpg object. The key in the examples is the value of X-Account-Meta-Temp-Url-Key.

Example: Create TempURL (in Python3)

import hmac
from hashlib import sha256
from sys import argv
from time import time

if len(argv) != 5:
  print 'Syntax: <method> <url> <seconds> <key>'
  print 'Example: GET https://storage101.dfw1.clouddrive.com/v1/' \
      'MossoCloudFS_12345678-9abc-def0-1234-56789abcdef0/' \
      'container/my_cat.jpg 60 my_shared_secret_key'
else:
  method, url, seconds, key = argv[1:]
  method = method.upper()
  base_url, object_path = object_url.split('/v1/')
  object_path = '/v1/' + object_path
  #  print object_url
  hmac_body = '%s\n%s\n%s' % (method, expires, object_path)
  temp_url_key_bytes = bytes(temp_url_key , 'latin-1')
  hmac_body_bytes = bytes(hmac_body, 'latin-1')
  temp_url_sig = hmac.new(temp_url_key_bytes, hmac_body_bytes, sha256).hexdigest()
  s = '{object_url}?temp_url_sig={temp_url_sig}&temp_url_expires={expires}'
  temp_url = s.format(object_url=object_url, temp_url_sig=temp_url_sig, expires=expires)

Be certain to use the full URL to the object, just as you would with a normal request.

In this example, the signature might be da39a3ee5e6b4b0d3255bfef95601890afd80709 and the expire time might translate to 1323479485 because the signature and expire time completely depend on the time when the code runs. On your website, you would provide a link to the following URL:

https://storage.clouddrive.com/v1/AUTH_account/container/my_cat.jpg?
temp_url_sig=da39a3ee5e6b4b0d3255bfef95601890afd80709&
temp_url_expires=1323479485

If you do not provide users with the exact TempURL, they get a 401 (Unauthorized) status code. HEAD queries are allowed if GET or PUT operations are allowed.

Example: Create TempURL (in PHP)

<?php
if ($argc != 5) {
    echo "Syntax: <method> <url> <seconds> <key>";
    echo "Example: GET https://storage101.dfw1.clouddrive.com/v1/" .
         "MossoCloudFS_12345678-9abc-def0-1234-56789abcdef0/" .
         "container/my_cat.jpg 60 my_shared_secret_key";
} else {
  $method = $argv[1];
  $url = $argv[2];
  $seconds = $argv[3];
  $key = $argv[4];
  $method = strtoupper($method);
  list($base_url, $object_path) =  split("/v1/", $url);
  $object_path = "/v1/$object_path";
  $seconds = (int)$seconds;
  $expires = (int)(time() + $seconds);
  $hmac_body = "$method\n$expires\n$object_path";
  $sig = hash_hmac("sha256", $hmac_body, $key);
  echo "$base_url$object_path?" .
       "temp_url_sig=$sig&temp_url_expires=$expires";
}
?>

Example: Create TempURL (in Ruby)

require "openssl"

unless ARGV.length == 4
    puts "Syntax: <method> <url> <seconds> <key>"
    puts ("Example: GET https://storage101.dfw1.clouddrive.com/v1/" +
        "MossoCloudFS_12345678-9abc-def0-1234-56789abcdef0/" +
        "container/path/to/object.file 60 my_shared_secret_key")
else
    method, url, seconds, key = ARGV
    method = method.upcase
    base_url, object_path = url.split(/\/v1\//)
    object_path = '/v1/' + object_path
    seconds = seconds.to_i
    expires = (Time.now + seconds).to_i
    hmac_body = "#{method}\n#{expires}\n#{object_path}"
    sig = OpenSSL::HMAC.hexdigest("sha256", key, hmac_body)
    puts ("#{base_url}#{object_path}?" +
        "temp_url_sig=#{sig}&temp_url_expires=#{expires}")
end

Override TempURL file names#

TempURLs support the filename query parameter, which you can use to override the Content-Disposition header and indicate to the browser a file name in which to save the file. In the following example, you see the usual TempURL without the file name override.

Example: TempURL without file name override

https://cf-cluster.example.com/v1/AUTH_account/container/object?
temp_url_sig=da39a3ee5e6b4b0d3255bfef95601890afd80709&
temp_url_expires=1323479485

In the following example, you see &filename=bob.txt appended to the TempURL to indicate to the browser to save the file as bob.txt:

Example: TempURL with file name override - Example 1

https://cf-cluster.example.com/v1/AUTH_account/container/object?
temp_url_sig=da39a3ee5e6b4b0d3255bfef95601890afd80709&
temp_url_expires=1323479485&
filename=bob.txt

With GET TempURLs, a Content-Disposition header is set on the response so that browsers interpret this as a file attachment to be saved. The file name chosen is based on the object name, but you can override this with a filename query parameter. The following example specifies a filename of My Test File.pdf:

Example: TempURL with file name override - Example 2

https://cf-cluster.example.com/v1/AUTH_account/container/object?
temp_url_sig=da39a3ee5e6b4b0d3255bfef95601890afd80709&
temp_url_expires=1323479485&
filename=My+Test+File.pdf

If you do not want the object to be downloaded, you can cause Content-Disposition: inline to be set on the response by adding the inline parameter to the query string:

Example: TempURL with inline query parameter

https://cf-cluster.example.com/v1/AUTH_account/container/object?
temp_url_sig=da39a3ee5e6b4b0d3255bfef95601890afd80709&
temp_url_expires=1323479485&
inline

FormPost#

You can use the FormPost feature to give your website audience a way to upload objects to your Cloud Files account through a web form. FormPost works by translating a browser form request into an object PUT operation in Cloud Files. After you enable FormPost on your account, you need only to create the form in your website by using the guidelines in this section.

As with all objects in Cloud Files, the object file size limit is 5 GB. If your users try to upload an object larger than 5 GB, they will get a file size error.

Set account metadata key#

To allow FormPost actions on your Cloud Files account, you must first set the X-Account-Meta-Temp-Url-Key metadata header on your Cloud Files account to a key that only you know. This key can be any arbitrary sequence.

After you set the key, do not change it while you still want others to access your account. If you change it, the actions from a FormPost become invalid (within 60 seconds, which is the cache time for a key).

Note

The POST URI should not include the final container. Include just the version and your account, like /v1/MossoCloudFS_0672d7fa-9f85-4a81-a3ab-adb66a880123 shown in the example below. If you include the full path to the container, the key is not set properly.

Example: Set account metadata key for public access: HTTP request

POST /v1/MossoCloudFS_0672d7fa-9f85-4a81-a3ab-adb66a880123 HTTP/1.1
Host: storage.clouddrive.com
X-Auth-Token: f064c46a782c444cb4ba4b6434288f7c
X-Account-Meta-Temp-Url-Key: yourKey

Any class 200 status code indicates success.

Create the form#

To communicate between your website and your Cloud Files account, create a form using the following format in your website:

Example: Layout of web form

<form action="<CF-url>" method="POST" enctype="multipart/form-data">
  <input type="hidden" name="redirect" value="<redirect-url>" />
  <input type="hidden" name="max_file_size" value="<bytes>" />
  <input type="hidden" name="max_file_count" value="<count>" />
  <input type="hidden" name="expires" value="<unix-timestamp>" />
  <input type="hidden" name="signature" value="<hmac>" />
  <input type="hidden" name="x_delete_at" value="<unix-timestamp>" />
  <input type="hidden" name="x_delete_after" value="<seconds>" />
  <input type="file" name="file1" /><br />
  <input type="submit" />
</form>

The parameters and attributes in the form are defined as follows:

  • (Required) The form action attribute is the Cloud Files URL (CF-url) to the destination where files will be uploaded. For example, https://storage.clouddrive.com/v1/yourAccountID/container. The name of each uploaded object has the <CF-url> appended to the front of it.

    Note

    Optionally, you can also include a prefix to separate uploads, such as assigning each user a certain prefix:

    https://storage.clouddrive.com/v1/yourAccountID/container/object_prefix

  • (Required) The method attribute must be POST and the enctype must be set as multipart/form-data.

  • (Optional) The redirect attribute is the URL of the page that is displayed on your website after the form processes. The URL will have status and message query parameters added to it, indicating the HTTP status code for the upload (2nn indicates success) and a possible message for more information if there is an error, such as max_file_size exceeded.

    Note

    Although the redirect attribute is optional for the form, it must be present in the HMAC body (shown in the following example). Although redirect must be present, its value can be an empty string to indicate that no redirect is included on the form.

  • (Required) The max_file_size attribute specifies the maximum size in bytes of the largest single file upload. Because the storage system maximum file size is 5 GB, max_file_size cannot exceed 5 GB.

  • (Required) The max_file_count attribute specifies the maximum number of files that can be uploaded with the form. If you send more files than specified by max_file_count, Cloud Files uploads the files as normal until you hit the limit (the max_file_count value). Then, Cloud Files sends an error when it is trying to create the file over the max_file_count value.

    Note

    The max_file_count value used to generate the signature must be the same as that in the web form.

  • (Required) The expires attribute is the UNIX timestamp when the form is invalidated. This gives your website users a limited time to have the form open. Time must be in UNIX epoch format.

    Note

    The expires in the web form and expires in the HMAC must be the same.

  • (Required) The signature attribute is the HMAC-SHA1 signature of the form. Following is sample code for computing the signature in Python:

    Example: Generate signature for FormPost

    import hmac
    from hashlib import sha1
    from time import time
    path = '/v1/account/container/object_prefix'
    redirect = 'https://myserver.com/some-page'  # set to '' if redirect not in form
    max_file_size = 104857600
    max_file_count = 10
    expires = int(time() + 600)
    key = 'mykey'
    hmac_body = '%s\n%s\n%s\n%s\n%s' % (path, redirect,
        max_file_size, max_file_count, expires)
    signature = hmac.new(key, hmac_body, sha1).hexdigest()
    

    Be sure to use the full path in your Cloud Files account, from the /v1/ onward.

    Note that x_delete_at and x_delete_after (see below) are not used in signature generation because they are optional attributes.

    The key value is the value of the X-Account-Meta-Temp-Url-Key header set for the account.

    Note

    If you receive the Invalid Signature error, use the HEAD operation to confirm that your key matches the value in the response from the HEAD command.

  • (Optional) If you want the uploaded files to be temporary, you can set the x-delete-at or x-delete-after attributes by adding one of these as a form input.

  • (Required) The type="file" attribute defines the form file field. You must have at least one entry to allow your users to select and upload a file, but you can add more fields for multiple files. However, the number of entries must not exceed the value of max_file_count. Each type="file" attribute must have a different name.

    Note

    The type="file" attribute or attributes must be at the end of the form code for Cloud Files to process the uploads correctly.

CORS#

Cross-Origin Resource Sharing (CORS) is a mechanism that allows code running in a browser to make requests to a domain other than the one from which it originated by using HTTP headers, such as those assigned by Cloud Files API requests.

Cloud Files supports CORS requests to containers and objects.

For more information about CORS and the access control headers, see www.w3.org/TR/access-control/.

CORS headers for containers#

Container-level headers for CORS are used for the following Cloud Files features:

  • FormPost to enable your users to post to your site

  • TempURL to limit how long users can use a given URL

Note

Container-level headers for CORS are not inherited for use with a CDN. For information about using object-level headers, which enable CORS to work over a CDN, see CORS headers for objects.

CORS container headers enable your users to upload files from one website, or origin, to your Cloud Files account. When you set the CORS headers on your container, you provide Cloud Files with the following information:

  • Which sites can post to your account

  • How often your container checks its allowed sites list

  • What headers to expose to the browser in the request response

CORS metadata is held on the container only. The values given apply to the container itself and all objects within it.

The following table lists the container-level headers:

Table: CORS container-level headers

X-Container-Meta-Access-Control-Allow-Origin

Specifies the origins that are allowed to make cross-origin requests, separated by a space when there are multiple values.

X-Container-Meta-Access-Control-Max-Age

Specifies the maximum age for the origin to hold the preflight results, in seconds (for example, 5, 10, or 1000).

X-Container-Meta-Access-Control-Allow-Headers

Specifies the headers that are allowed in the actual request, separated by a space when there are multiple values.

X-Container-Meta-Access-Control-Expose-Headers

Indicates the headers exposed to the browser in the actual request response, separated by a space when there are multiple values.

To view the values for these headers, use the HEAD operation to show container metadata. To delete the metadata, use the DELETE operation to delete container metadata. (See Show container metadata and Delete container metadata for descriptions of these operations.)

Before a browser issues an actual request, it might issue a preflight request. The preflight request is an HTTP OPTIONS call to verify that the origin is allowed to make the request. Following is the sequence of actions:

  1. The browser makes an OPTIONS request to Cloud Files.

  2. Cloud Files returns either a 200 or 401 status code to the browser based on the allowed origins.

  3. If Cloud Files returns 200, the browser makes the actual request (DELETE, GET, HEAD, POST, PUT) to Cloud Files.

When a browser receives a response to an actual request, it exposes only those headers listed in the X-Container-Meta-Access-Control-Expose-Headers header. By default, Cloud Files returns the following values for this header:

  • The simple response headers as listed at www.w3.org/TR/cors/#simple-response-header/

  • The ETag, X-Timestamp, and X-Trans-Id headers

  • All metadata headers (X-Container-Meta-* for containers and X-Object-Meta-* for objects)

  • Headers listed in X-Container-Meta-Access-Control-Expose-Headers

To see some CORS JavaScript in action, follow these steps:

  1. Copy and paste the text from Example: Test CORS page at the bottom of this section.

  2. Host the page on a web server and note the protocol and hostname (origin) you will be using to request the page, for example http://localhost.

  3. Locate a container that you want to query. (The Cloud Files cluster hosting this container must have CORS support.)

  4. Append the origin of the test page to the container’s X-Container-Meta-Access-Control-Allow-Origin header, using a request similar to the following example.

Example of a CORS POST cURL request

curl -X POST -H 'X-Auth-Token: yourAuthToken' \
  -H 'X-Container-Meta-Access-Control-Allow-Origin: http://localhost' \
   https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_0672d7fa-9f85-4a81-a3ab-adb66a880123/MyContainer

At this point, the container is accessible to CORS clients hosted on http://localhost. Open the test CORS page in your browser and following these steps:

  1. Populate the Token field.

  2. Populate the URL field with the URL of either a container or object.

  3. Select the request method.

  4. Hit Submit.

If the request succeeds, the response header and body are displayed. If the request did not succeed, the response status is 0.

Example: Test CORS page

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Test CORS</title>
  </head>
  <body>

    Token<br><input id="token" type="text" size="64"><br><br>

    Method<br>
    <select id="method">
        <option value="GET">GET</option>
        <option value="HEAD">HEAD</option>
        <option value="POST">POST</option>
        <option value="DELETE">DELETE</option>
        <option value="PUT">PUT</option>
    </select><br><br>

    URL (Container or Object)<br><input id="url" size="64" type="text"><br><br>

    <input id="submit" type="button" value="Submit" onclick="submit(); return false;">

    <pre id="response_headers"></pre>
    <p>
    <hr>
    <pre id="response_body"></pre>

    <script type="text/javascript">
      function submit() {
          var token = document.getElementById('token').value;
          var method = document.getElementById('method').value;
          var url = document.getElementById('url').value;

          document.getElementById('response_headers').textContent = null;
          document.getElementById('response_body').textContent = null;

          var request = new XMLHttpRequest();

          request.onreadystatechange = function (oEvent) {
              if (request.readyState == 4) {
                  responseHeaders = 'Status: ' + request.status;
                  responseHeaders = responseHeaders + '\nStatus Text: ' + request.statusText;
                  responseHeaders = responseHeaders + '\n\n' + request.getAllResponseHeaders();
                  document.getElementById('response_headers').textContent = responseHeaders;
                  document.getElementById('response_body').textContent = request.responseText;
              }
          }

          request.open(method, url);
          request.setRequestHeader('X-Auth-Token', token);
          request.send(null);
      }
    </script>

  </body>
</html>

CORS headers for objects#

You can set object-level headers for CORS. Currently, using object-level headers enables CORS to work over a CDN.

The following table lists the object-level headers:

Table: CORS object-level headers

Access-Control-Allow-Origin

Specifies the origins that are allowed to make cross-origin requests, separated by a space when there are multiple values.

Access-Control-Max-Age

Specifies the maximum age for the origin to hold the preflight results, in seconds (for example, 5, 10, or 1000).

Access-Control-Expose-Headers

Specifies the headers exposed to the browser in the actual request response, separated by a space when there are multiple values.

Access-Control-Allow-Credentials

Indicates whether or not the response to the request can be exposed when the credentials flag is true. When used as part of a response to a preflight request, this indicates whether or not the actual request can be made using credentials. Note that simple GET requests are not preflighted, and so if a request is made for a resource with credentials, if this header is not returned with the resource, the response is ignored by the browser and not returned to web content.

Access-Control-Allow-Methods

Specifies the method or methods allowed when accessing the resource. This is used in response to a preflight request.

Access-Control-Request-Headers

Used when issuing a preflight request to let the server know what HTTP headers will be used when the actual request is made.

Access-Control-Request-Method

Used when issuing a preflight request to let the server know what HTTP method will be used when the actual request is made.

Origin

Indicates the origin of the cross-site access request or preflight request.

The following example assigns the file origin to the Origin header to indicate where the file came from. Doing so allows you to provide security that requests to your Cloud Files repository are indeed from the correct origination.

Example: Assign CORS header request for an object

PUT /apiVersion/yourAccountID/containerName/objectName HTTP/1.1
Host: storage.clouddrive.com
X-Auth-Token: yourAuthToken
Origin: http://storage.clouddrive.com