Using CORS to process cross-domain requests
HCP supports Cross-Origin Resource Sharing (CORS). CORS is a mechanism that uses additional HTTP headers to allow a web application running on a browser at one origin (domain) to have permission to access restricted resources on a server at a different origin. A web application executes a cross-origin HTTP request when it requests a resource that has a different origin (domain, protocol, and port) than its own.
To use CORS with HCP, you first need to configure CORS rules for a namespace to specify the sites that are allowed cross-origin access. Then, the HCP software validates incoming requests for compliance to these rules.
CORS rules are specific to a namespace and can be configured at either the namespace level or tenant level.
CORS use cases
With a proper CORS rules configuration for a namespace, the HCP software can process CORS requests from web applications hosted in a different domain (origin).
HCP supports the following CORS use cases.
A simple request is a request that does not trigger a CORS preflight request. A simple request meets the following conditions:
- The method request is GET, HEAD, or POST.
- The only headers added manually are
Accept
,Accept-Language
,Content-Language
,Content-Type
,DPR
,Downlink
,Save-Data
,Viewport-Width
,Width
. - The
Content-Type
header value isapplication/x-www-form-urlencoded
,multipart/form-data
, ortext/plain
. - No
ReadableStream
object or event listeners are registered on anyXMLHttpRequestUpload
object that the request uses.
A preflight request is a CORS request that checks to see if the CORS protocol is understood. It is an OPTIONS request that uses three HTTP request headers:
Access-Control-Request-Method
Access-Control-Request-Headers
Origin
A web browser automatically issues a preflight request when needed. The browser determines whether it needs to send a preflight request based on the web application request parameters used in the JavaScript code. If the HCP server approves the validity of the preflight request, the server responds with an approval response header. Then, the web browser sends the actual HTTP resource request.
If any of the following conditions is true, the browser uses a preflight request before the actual resource request:
- The request uses the
Authorization
header. - The request uses one of these methods: PUT, DELETE, OPTIONS.
- The request uses headers and a
Content-Type
other than the ones used for a simple request (described above). - The request contains event listeners registered on an
HTMLHttpRequestUpload
object or aReadableStream
object.
CORS limits
The HCP implementation of CORS has several limits.
A CORS rules configuration in HCP can have any number of CORSRule
, AllowedMethod
, AllowedOrigin
, and AllowedHeader
elements. However, the maximum size of the CORS configuration cannot exceed 2.5 MB.
To safeguard an HCP instance, HCP does not support preflighted CORS requests for namespaces with path-style and virtual-path URLs that include the following reserved keywords:
- rest
- webdav
- fcfs_data
- browser
- hs3
- swift
CORS does not support tenant-level API calls (S3 compatible API, REST API, HCP management API).
CORS rules configuration
Namespaces (buckets) to which you would like to allow cross-origin access must first be configured with CORS rules.
A CORS rules configuration is an XML document with rules that describe the external origins (domains), HTTP methods (operations), and HTTP headers that are allowed access to each bucket. You add the XML document to a bucket as a CORS subresource either programmatically or by using the Tenant Management Console or System Management Console, as described next.
CORS rules can be configured at the namespace level or tenant level.
- To configure CORS rules for a namespace, use one of these interfaces:
- Tenant Management Console
- S3 compatible API
- HCP management API
- To configure CORS rules at the tenant level to server as the default for all namespaces owned by a tenant, use one of these interfaces:
- System Management Console
- HCP management API
Setting CORS rules at the tenant level supports deployments in which a large number of HCP namespaces support the same CORS configuration.
- If a namespace managed by the tenant does not have a CORS configuration, the namespace inherits the tenant-level configuration.
- If a namespace has its own CORS configuration, the namespace-level configuration overrides the tenant-level configuration.
HCP permissions for CORS configuration
Users with the administrator or monitor role can read CORS settings at the namespace level or tenant level. Users with the administrator role can also modify CORS settings at the namespace level or tenant level.
The HCP software makes the following distinction between system-level users and tenant-level users. Typically, system-level users do not have tenant management capabilities. However, there is a configuration that grants system-level users tenant-management capabilities. In such instances, system-level users are allowed to configure CORS rules with the Tenant Management Console or HCP management API under the same read/write permissions described above.
The S3 compatible API makes the following distinction. When a system-level user has the administrator role and Allow system-level users to manage this tenant and search its namespaces in the Tenant Management Console is enabled:
- The system-level user can perform namespace-level configuration operations with the HCP Authentication header.
- The system-level user cannot perform namespace-level configuration operations with the Amazon Web Services (AWS) Authorization header (AWS Signature Version 2 or AWS Signature Version 4).
Request header and elements
A CORS rules configuration uses the request header and elements described in the next tables. Some of the request elements are optional.
Content-MD5
The base64-encoded 128-bit MD5 digest of the data. This header must be used as a message integrity check to verify that the request body was not corrupted in transit.
CORSConfiguration
Container for
CORSRules
elements.Type: Container
Children:
CORSRules
Ancestor: None
A CORS rules configuration in HCP can have any number of
CORSRule
,AllowedMethod
,AllowedOrigin
, andAllowedHeader
elements. However, the maximum size of the CORS configuration cannot exceed 2.5 MB.CORSRule
A set of origins and methods that you want to allow to access a resource.
Type: Container
Children:
AllowedMethod
,AllowedOrigin
,AllowedHeader
,MaxAgeSeconds
,ExposeHeader
Ancestor:
CORSConfiguration
Id
Optional
A unique identifier for the rule. The Id value assists you in finding a rule in the CORS configuration.
Type: String
Ancestor: CORSRule
AllowedMethod
HTTP methods that you want to allow the origin to execute. Each
CORSRule
must identify at least one origin and one method.Type: Enum (GET, PUT, HEAD, POST, DELETE)
Ancestor:
CORSRule
AllowedOrigin
Origins that you want to allow cross-origin requests from. Each
CORSRule
must identify at least one origin and one method.The origin value can include at most one wildcard character "*", for example, http://*.example.com. Alternatively, you can specify thewildcard character by itself to enable all origins to send cross-origin requests.
Type: String
Ancestor:
CORSRule
AllowedHeader
Optional
List of headers that are allowed in a preflight OPTIONS request through the
Access-Control-Request-Headers
header. This element can contain at most one wildcard character "*". Each header name in theAccess-Control-Request-Headers
header must have a corresponding entry in theCORSRule
. The server will send only the allowed headers that were requested in a response.Type: String
Ancestor:
CORSRule
MaxAgeSeconds
Optional
Maximum time, in seconds, that the browser can cache a preflight OPTIONS response for a specified resource. By caching the response, the browser does not have to send preflight requests to the server within the
MaxAgeSeconds
time window if repeated requests (same origin, HTTP method, and resource) are issued.A
CORSRule
can have at most one MaxAgeSeconds element.Type: Integer (seconds)
Ancestor: CORSRule
ExposeHeader
Optional
One or more response headers that customers can access from their applications, for example, from a JavaScript
XMLHttpRequest
object.You add one
ExposeHeader
element in the rule for each header. This element restricts the response headers that are accessible by the client.Type: String
Ancestor:
CORSRule
Example: PUT bucket request
The following PUT bucket request adds a CORS subresource to a bucket (namespace) named finance.
PUT /?cors HTTP/1.1 Host:finance.europe.hcp.example.com x-amz-date: Tue, 14 May 2019 17:54:50 GMT Content-MD5: 8dYiLewFWZyGgV2Q5FNI4W== Authorization: SignatureString
<CORSConfiguration>
<CORSRule>
<AllowedOrigin>http://www.example.com</AllowedOrigin>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>DELETE</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
<MaxAgeSeconds>3000</MaxAgeSec>
<ExposeHeader>ETag</ExposeHeader>
</CORSRule>
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
<MaxAgeSeconds>3000</MaxAgeSeconds>
</CORSRule>
</CORSConfiguration>
HTTP/1.1 200 OK Date: Tue, 14 May 2019 17:54:50 GMT Server: HCP
Example: GET bucket request
The following GET bucket request returns a CORS subresource from a bucket (namespace) named finance.
GET /?cors HTTP/1.1 Host:finance.europe.hcp.example.com Date: Tue, 14 May 2019 2 17:54:50 GMT Authorization: SignatureString
HTTP/1.1 200 OK Date: Tue, 14 May 2019 19:14:42 GMT Server: HCP Content-Length: 280
<CORSConfiguration>
<CORSRule>
<AllowedOrigin>http://www.example.com</AllowedOrigin>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>DELETE</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
<MaxAgeSeconds>3000</MaxAgeSec>
<ExposeHeader>ETag</ExposeHeader>
</CORSRule>
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
<MaxAgeSeconds>3000</MaxAgeSeconds>
</CORSRule>
</CORSConfiguration>
Example: DELETE bucket request
The following DELETE bucket request deletes a CORS subresource from a bucket (namespace) named finance.
DELETE /?cors HTTP/1.1 Host:finance.europe.hcp.example.com Date: Tue, 14 May 2019 19:14:42 GMT Authorization: SignatureString
HTTP/1.1 204 No Content Date: Tue, 14 May 2019 19:14:42 GMT Server: HCP Content-Length: 0
CORS request validation
After CORS rules are configured for an HCP namespace, web applications can request access to the namespace resources by using either the Hitachi API for Amazon S3 or the REST API.
The Amazon S3 and REST gateways perform CORS rules validation on incoming object requests against an HCP bucket. When a CORS compliant HCP server receives a bucket request from a browser, the server evaluates the request headers against the CORS rules configuration for the bucket. The first CORS rule for the bucket that matches the request is the rule that is applied for creating the server response headers.
For security reasons, requests that fail authentication are not validated. In the web browser, these failed authentication requests result in CORS errors.
Request headers are automatically set when a web browser issues an HTTP request to an HCP server.
The following list describes the runtime request headers sent by a browser depending on the request type (simple or preflight).
Origin
Request type: Simple, Preflight
Origin of the cross-domain request. For example, http://www.example.com
Access-Control-Request-Method
Request type: Preflight
HTTP method to be used when the request is made.
Access-Control-Request-Headers
Request type: Preflight
Headers used when the request is made. The format for the headers is a comma-separated list. If any of the headers are not contained in a CORS rule, the preflight request and CORS access to the server are denied, and the subsequent request is not issued.
In response to a CORS simple or preflighted request from the browser, the HCP server responds with the corresponding CORS headers.
The following list describes the CORS response headers.
Access-Control-Allow-Origin
Request type: Simple, Preflight
This response header indicates whether the response can be shared with the requesting code from the origin.
If no applicable CORS rule is defined on the server, the
Access-Control-Allow-Origin
header is not defined in the response, which causes the browser to deny access to the resource.A '*' wildcard character by itself means that the resource is public and available to everyone. Using '*' as the value of this header with credentials will result in an error. For more information, see the
Access-Control-Allow-Credentials
response header description in this table.Access-Control-Allow-Headers
Request type: Preflight
Returned by the server in response to a preflight request that includes the
Access-Control-Request-Headers
header to indicate which HTTP headers can be used during the actual request.Only returned for the OPTIONS request, not for the preflighted API call.
Access-Control-Allow-Methods
Request type: Preflight
Returned by the server in response to a preflight request to specify the HTTP method or methods allowed when the actual request is made.
Only returned for the OPTIONS request, not for the preflighted API call.
Access-Control-Expose-Headers
Request type: Simple, Preflight
Optional
Headers that browsers are allowed to access. By default, only six simple response headers are exposed:
- cache-control
- content-language
- content-type
- expires
- last-modified
- pragma
Only returned for the OPTIONS request, not for the preflighted API call.
Access-Control-Max-Age: delta-seconds
Request type: Preflight
Optional
Indicates how long the results of a preflight request can be cached in the browser.
Access-Control-Allow-Credentials: true
Request type: Simple, Preflight
Optional
When used in a response to a preflight request, this header indicates whether the actual request can be made with credentials.
For a simple request, if the header is true, the response is ignored by the browser and no content is returned to the web browser. This header works in conjunction with the credentials option (XHR or Fetch request).
HCP returns the true value for this header unless the
AllowedOrigin
element in the CORS rules configuration is defined as "*"; in the latter case, theAccess-Control-Allow-Credentials
header is not returned.NoteA CORS compliant HCP server will not return theAccess-Control-Allow-Credentials
header when the wildcard character "*" is defined asAllow-Origin
and the value of theAccess-Control-Allow-Origin
response header is "*".Vary
Request type: Simple, Preflight
This response header determines how to match future request headers to determine whether a cached response can be used rather than requesting a new response from the server.
If the HCP server sends a response with an
Access-Control-Allow-Origin
value that is an explicit origin (rather than the wildcard character "*"), the response should also include aVary
response header with theOrigin
value to indicate that server responses can differ based on the value of theOrigin
request header.The value of the Vary header is a comma separated list of header names that can change. For example:
Vary: Origin, Access-Control-Request-Headers, Access-Control-Request-Method
Here is an sample CORS preflighted request.
The preflighted request comprises two exchanges: an HTTP OPTIONS request (preflight request) from a web browser in one domain to a server in another domain to determine whether the actual request is safe to send, followed by the actual request.
Request headers (Preflight request)
OPTIONS rest/file.txt HTTP/1.1 Host: finance.europe.hcp.example.com User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Safari/537.36 Access-Control-Request-Headers: Authorization Access-Control-Request-Method: GET Origin: http://lgreen.example.com Referer: http://lgreen.example.com/cors/rest.html
Response headers (Preflight request)
HTTP/1.1 200 OK Access-Control-Allow-Headers: Authorization Access-Control-Allow-Methods: GET, PUT, DELETE, POST, HEAD Access-Control-Allow-Origin: * Cache-Control: no-cache,no-store,must-revalidate Content-Length: 0 Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; connect-src 'self'; img-src 'self'; style-src 'self' 'unsafe-inline'; object-src 'self'; frame-ancestors 'self'; Date: Tue, 07 May 2019 14:45:08 GMT Expires: Thu, 01 Jan 1970 00:00:00 GMT Pragma: no-cache Strict-Transport-Security: max-age=31536000; includeSubDomains Vary: Origin, Access-Control-Request-Headers, Access-Control-Request-Method X-Content-Type-Options: nosniff X-DNS-Prefetch-Control: off X-Download-Options: noopen X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block
In this example, the first exchange is complete. The server evaluated the preflight request against the CORS rules configuration for the resource, and responded that it is acceptable for the browser to send the actual request parameters: a GET request to a bucket named finance
for an object named rest/file.txt.
Request headers (Actual request)
GET rest/file.txt HTTP/1.1 Host:finance.europe.hcp.example.com User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Safari/537.36 Origin:http://lgreen.example.com
Response headers (Actual request)
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://lgreen.example.com
Access-Control-Expose-Headers: ETag
Response body (Actual request)
[contents of the rest/file.txt object]