Delegated dialogs allow one application to embed a creation or selection UI into another using HTML
iframe
elements and JavaScript code. The embedded dialog notifies the parent page of resize or
submit events using HTML5 postMessage
.
OSLC specifications target specific integration scenarios. In some cases, allowing one application to delegate to a user interface defined in another application is a more effective way to support a use case than an HTTP interface that can only be accessed programmatically. There are two cases where this is especially true:
Delegated dialogs support these two cases. They allow one application to embed a creation or selection UI into
another using HTML iframe
elements and JavaScript code.
depicts what a defect creation dialog might look like inside a quality management tool, displayed when the user clicks the Open Bug button. The dialog content itself comes from the change management tool, running on another server. The dialog displays seamlessly inside the quality management application, however, while retaining the change management tool's look and feel and capabilities.
Delegated dialogs provide a simple way for an end user to create or select resources from another application, thus eliminating the need to rebuild the other application's dialog and its application logic.
Terminology uses and extends the terminology and capabilities of OSLC Core Overview, W3C Linked Data Platform [[!LDP]], W3C's Architecture of the World Wide Web [[WEBARCH]], and Hyper-text Transfer Protocol [[!HTTP11]].
The following terms are used in discussions of dialogs:
oslc:Dialog
. See
.
Clients can discover dialogs in three ways:
LDP containers [[!LDP]] advertise their support for dialogs using the HTTP Link
header
[[!RFC8288]]. Each dialog type, creation or selection, has its own link relation.
Dialog Type | Link Relation |
---|---|
Creation | http://open-services.net/ns/core#creationDialog |
Selection | http://open-services.net/ns/core#selectionDialog |
The client discovers the dialogs by making an HTTP OPTIONS request on the container.
OPTIONS /bugs/ HTTP/1.1 Host: example.com
The server response contains a Link
header with URLs to the dialog descriptors.
HTTP/1.1 204 No Content Date: Thu, 12 Jun 2014 18:26:59 GMT Allow: GET,POST,OPTIONS,HEAD Accept-Post: text/turtle,application/ld+json Link: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type", <http://www.w3.org/ns/ldp#Resource>; rel="type", <http://example.com/dialogs/createBug>; rel="http://open-services.net/ns/core#creationDialog", <http://example.com/dialogs/selectBug>; rel="http://open-services.net/ns/core#selectionDialog"
The client then requests the dialog descriptor which contains an oslc:dialog
property whose value
is a link to the HTML dialog to be displayed.
GET /dialogs/selectBug HTTP/1.1 Host: example.com
HTTP/1.1 200 OK Content-Type: text/turtle Transfer-Encoding: chunked @prefix oslc: <http://open-services.net/ns/core#> . @prefix dcterms: <http://purl.org/dc/terms/> . <> a oslc:Dialog ; oslc:dialog <http://example.com/dialogs/selectBug/form> ; oslc:hintHeight "600px" ; oslc:hintWidth "400px" ; oslc:label "Select Bug" ; oslc:resourceType <http://open-services.net/ns/cm#Bug> ; dcterms:title "Select Bug from Product Z" .
Clients can also use the HTTP Prefer
header to find the dialogs for a container. The client makes
an HTTP GET request on the resource URI using the return=representation
preference [[!RFC7240]]
and include
parameter [[!LDP]] value http://open-services.net/ns/core#PreferDialog
.
The server responds with the dialog descriptors in the response body. Clients should also use
include
parameter value http://www.w3.org/ns/ldp#PreferMinimalContainer
so that the
response doesn't include unnecessary data.
The following example shows a container that supports creation and selection dialogs:
GET /bugs/ HTTP/1.1 Host: example.com Accept: text/turtle Prefer: return=representation; include="http://open-services.net/ns/core#PreferDialog http://www.w3.org/ns/ldp#PreferMinimalContainer"
HTTP/1.1 200 OK Content-Type: text/turtle ETag: "_87e52ce291112" Link: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type", <http://www.w3.org/ns/ldp#Resource>; rel="type" Accept-Post: text/turtle, application/ld+json Allow: POST,GET,OPTIONS,HEAD Preference-Applied: return=representation Vary: Accept,Prefer Transfer-Encoding: chunked @prefix ex: <http://example.com/vocab#> . @prefix oslc: <http://open-services.net/ns/core#> . @prefix dcterms: <http://purl.org/dc/terms/> . @prefix ldp: <http://www.w3.org/ns/ldp#> . <http://example.com/bugs/> a ldp:BasicContainer ; oslc:creationDialog <http://example.com/dialogs/createBug> ; oslc:selectionDialog <http://example.com/dialogs/selectBug> ; dcterms:title "Bugs Records for Product Z" . <http://example.com/dialogs/createBug> a oslc:Dialog ; oslc:dialog <http://example.com/dialogs/createBug/form> ; oslc:hintHeight "600px" ; oslc:hintWidth "400px" ; oslc:label "New Bug" ; oslc:resourceType <http://open-services.net/ns/cm#Bug> ; dcterms:title "Report Bug (Product Z)" . <http://example.com/dialogs/selectBug> a oslc:Dialog ; oslc:dialog <http://example.com/dialogs/selectBug/form> ; oslc:hintHeight "600px" ; oslc:hintWidth "400px" ; oslc:label "Select Bug" ; oslc:resourceType <http://open-services.net/ns/cm#Bug> ; dcterms:title "Select Bug (Product Z)" .
Servers may also advertise their support for dialogs using the oslc:creationDialog
and
oslc:selectionDialog
properties of the Service discovery resource.
The client discovers the dialogs by making a GET request on the Service resource and accessing these properties.
GET /serviceproviders/bugs/services.xml HTTP/1.1 Host: example.com Accept: application/rdf+xml
The server response contains a Service resource which contains properties with URLs to the dialog descriptors.
HTTP/1.1 200 OK Date: Thu, 12 Jun 2014 18:26:59 GMT Content-Type: application/rdf+xml <?xml version="1.0" encoding="UTF-8"?> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:oslc="http://open-services.net/ns/core#"> <oslc:ServiceProvider rdf:about="https://example.com/serviceproviders/bugs/services.xml"> <oslc:creationDialog> <oslc:Dialog> <dcterms:title rdf:parseType="Literal">New Bug</dcterms:title> <oslc:label>Bug Change Request</oslc:label> <oslc:usage rdf:resource="http://open-services.net/ns/cm#requirementsChangeRequest"/> <oslc:resourceType rdf:resource="http://open-services.net/ns/cm#ChangeRequest"/> <oslc:dialog rdf:resource="http://example.com/dialogs/createBug/form"/> <oslc:hintWidth>680px</oslc:hintWidth> <oslc:hintHeight>505px</oslc:hintHeight> </oslc:Dialog> </oslc:creationDialog> <oslc:selectionDialog> <oslc:Dialog> <dcterms:title rdf:parseType="Literal">Select Bug</dcterms:title> <oslc:label>Bug</oslc:label> <oslc:usage rdf:resource="http://open-services.net/ns/core#default"/> <oslc:resourceType rdf:resource="http://open-services.net/ns/cm#ChangeRequest"/> <oslc:dialog rdf:resource="http://example.com/dialogs/selectBug/form"/> <oslc:hintWidth>550px</oslc:hintWidth> <oslc:hintHeight>460px</oslc:hintHeight> </oslc:Dialog> </oslc:selectionDialog> </oslc:ServiceProvider> </rdf:RDF>
The client then requests the dialog to display using the discovered URI in the
oslc:dialog
property in order to display the desired form.
GET /dialogs/selectBug/form HTTP/1.1 Host: example.com
Servers can offer two kinds of dialogs, selection dialogs and creation dialogs. Clients use selection dialogs when they want a user to pick a resource from another application. They use creation dialogs when they want a user to create a new resource in another application.
A client can open the dialog in a new browser window, or it can embed the dialog in another page by creating an
iframe
element and setting the src
attribute to the URI of the dialog to be included.
var iframe = document.createElement("iframe"); iframe.style.border = 0; iframe.style.width = "600px"; // or preferred dialog width iframe.style.height = "400px"; // or preferred dialog height iframe.src = "http://example.com/dialogs/createBug/form"; document.getElementById("dialogContainer").appendChild(iframe);
Clients might choose to place dialogs inside page elements styled to look like a dialog window.
The iframe
itself, outlined in , contains the dialog content from the
server.
Dialogs send results back to the client using the HTML5 function
Window.postMessage
[[!whatwg-web-messaging]]. postMessage
is called on
window.opener
if set. Otherwise, postMessage
is called on window.parent
.
When embedded in an iframe
, dialogs may also request to be resized dynamically. These requests are
the same as specified in OSLC Resource Preview and also use
postMessage
. Clients can distinguish between results and resize messages from the message prefix.
Messages have the following prefixes:
Message Prefix | Meaning |
---|---|
oslc-response: |
The user has created or selected resources or canceled the dialog. |
oslc-resize: |
The dialog is asking to be resized. |
A stringified JSON object will be concatenated to the message prefix. For dialog responses, the JSON is
described by . It is a JSON object with an oslc:results
array of
results. Each result is a JSON object with an rdf:resource
property whose value is the resource
URI. The result may also have an oslc:label
that can be useful for client to display a label for
the delegated dialog.
oslc-response:{"oslc:results": [{ "oslc:label": "bug 123: server crash", "rdf:resource": "http://example.com/bug123" }]}
An empty array indicates the dialog was canceled.
For resize requests, the JSON is an object with an oslc:hintHeight
property, an
oslc:hintWidth
property, or both.
oslc-resize:{"oslc:hintHeight": "277px", "oslc:hintWidth": "400px"}
Window.open()
method or embed the dialog in an
iframe
, setting iframe
src
to the URI of the dialog.
message
listener to receive messages from the dialog.message
events, ignoring unrecognized events from other sources or those not
prefixed with oslc-response:
window.addEventListener("message", function(event) { // Make sure the message originated from the same origin as the dialog. if (event.origin !== "http://example.com") { return; } // Make sure the message starts with oslc-response: var message = event.data; if (message.indexOf("oslc-response:") !== 0) { return; } // Handle each result. var response = JSON.parse(message.substr("oslc-response:".length)); var results = response["oslc:results"]; for (var i = 0; i < results.length; i++) { var label = results[i]["oslc:label"]; var uri = results[i]["rdf:resource"]; // Handle resource... } // Remove the dialog from the page. var dialogContainer = document.getElementById('dialogContainer'); dialogContainer.removeChild(dialogContainer.firstChild); }, false);
postMessage
to the page's opener or parent window prefixed with "oslc-response:"
.
The following JavaScript code example shows how a dialog would send a response using postMessage
,
taking into account pages that the dialog might be in its own window or an iframe
.
function respondWithSelection(label, uri) { var response = { "oslc:results": [ { "oslc:label": label, "rdf:resource": uri } ] }; (window.opener || window.parent).postMessage("oslc-response:" + JSON.stringify(response), "*"); }
Servers may support setting the initial values in a dialog. A client can test if a dialog supports prefill by making an HTTP OPTIONS request to the dialog descriptor URI. Prefill can be used with creation dialogs to provide a template of initial values. Clients can use prefill with selection dialogs to inform servers about the users desired content in the selection dialog.
OPTIONS /dialogs/createBug HTTP/1.1 Host: example.com
If the server supports prefill for this dialog, it includes POST among the methods in the
Allow
response header.
HTTP/1.1 204 No Content Allow: GET,POST,HEAD,OPTIONS
To prefill content, clients POST the resource representation with the desired initial values to the delegated dialog descriptor URI.
POST /dialogs/createBug HTTP/1.1 Host: example.com Content-Type: text/turtle Transfer-Encoding: chunked @prefix oslc_cm: <http://open-services.net/ns/cm#> . @prefix dcterms: <http://purl.org/dc/terms/> . <> a oslc_cm:Bug ; dcterms:title "Build 23 failed" ; oslc_cm:severity <http://example.com/enums#S1> .
The content of the request depends on the type of dialog and the server. Servers may describe constraints on
POST content using ResourceShapes. The dialog descriptor uses property
oslc:resourceShape
for the shape constraints.
The server's response contains a Location
header with the prefilled dialog's URI. The client uses
this as the iframe src
.
HTTP/1.1 201 Created Location: http://example.com/dialogs/createBug/form/2zFy45
The client then uses the dialog URI from the Location
like any other dialog. The dialog URI from
a prefill request is often temporary. After a reasonable time, the server might respond with 404 Not Found or
410 Gone.
Clickjacking is a vulnerability that can occur when a malicious (or compromised) web application embeds an OSLC delegated dialog in the application in such a way that the user is tricked into using their authenticated session with the dialog, believing that they are performing an operation other than the one indicated on the delegated dialog. The clickjacking application embeds it own web page in a way that means the dialog is not clearly visible to the user, either almost invisible, or hidden behind other components). When the user attempts to click on the visible components, the browser interprets this as a click on the obscured delegated dialog, and the components within it. The malicious web page encourages the user to click one of the visible components, which the user might believe will not have side-effects (such as a link saying "If you are not redirected within 2 seconds, click here"), but places that component over a component in the delegated dialog that the malicious page wishes the user to click unknowingly. The user attempts to click on the visible component, but the browser interprets that as a click on the hidden component, which will perform some action that the user is authorised to do (but the malicious web page is not) but that the user did not intend to perform.
This vulnerability requires that the user loads a malicious web page in their browser. This can happen in a number of ways, including:
There are always two pages involved in this attack; the "UI consumer" page (which has the iframe embedded within it), and the "UI provider" page (which gets loaded within the iframe). Consider the UI provider's server the "server under attack".
To protect against this attack:
X-Frame-Options
header with value SAMEORIGIN or DENY.
This is only required on dialogs or resource previews that contain controls that can be invoked with one or more clicks, and where those controls have side effects on the server. That is, if there are no controls on a preview, then there is no target for the malicious page to tick the user to click on.
By following these steps the server under attack knows that only clients that are able to authenticate against the server (e.g. for OAuth authentication they must have a valid client ID and - if required by the interaction pattern they're using - they must know the client secret), and that have also been authorized by the user to whom the the dialog is displayed, can display that dialog.
There are still some potential attack vectors:
But the exposure has been reduced as the attack cannot occur simply by loading a malicious web page in the user's browser. See the OWASP Clickjacking Defense Cheat Sheet for further information.
In responses to successful HTTP requests for an LDP container that has a selection dialog, server MUST
include a Link
header [[!RFC5988]] where:
http://open-services.net/ns/core#selectionDialog
, andLink: <http://example.com/dialogs/selectBug>; rel="http://open-services.net/ns/core#selectionDialog"
In responses to successful HTTP requests for an LDP container that has a creation dialog, server MUST
include a Link
header [[!RFC5988]] where:
http://open-services.net/ns/core#creationDialog
, andLink: <http://example.com/dialogs/createBug>; rel="http://open-services.net/ns/core#creationDialog"
Clients MAY request that the dialog descriptors for an LDP container are returned inline using the
Prefer
request header [[!RFC7240]] with:
return
, value representation
include
[[!LDP]], value http://open-services.net/ns/core#PreferDialog
.
Prefer: return=representation; include="http://open-services.net/ns/core#PreferDialog"
Servers MUST honor a client's request to inline dialog descriptors if the target resource has any dialog descriptors and the request is successful.
Servers MUST express the oslc:hintWidth
and oslc:hintHeight
properties of an
oslc:Dialog
in length units as specified in [[!CSS21]].
In responses to HTTP GET requests targeting resources that have dialogs, servers SHOULD either include a
Vary
response header with at least Accept
and Prefer
field values or a
Cache-Control
header value no-store
.
Servers MAY also provide delegated dialog discovery using the
ServiceProvider and
Service resource and the oslc:creationDialog
and
oslc:selectionDialog
properties.
When embedding a dialog inside another web page, the client MUST use an iframe
element and set
the its src
attribute to the URI of the dialog.
In order to allow the dialogs to be loaded on another webpage, the server SHOULD allow embedding dialogs on trusted domains by following the [[!CSP]] specification.
Servers MUST support the Window.postMessage
method [[!whatwg-web-messaging]] for dialog
responses.
Servers MAY support the Window Name Protocol defined in [[!OSLCCore2]] for backward compatibility with OSLC 2.0 clients that use that protocol.
Servers MAY support other protocols for dialog responses not specified in this document, which clients request by appending a fragment identifier [[!RFC3986]] describing the protocol to the end of the dialog URI.
Servers MUST use postMessage
for dialog responses if a client has not added a fragment identifier
to the dialog URI, or the fragment identifier is #oslc-core-postMessage-1.0
.
Messages describing dialog results MUST start with the characters
oslc-response:
followed by JSON as specified in .
oslc-response:{"oslc:results": [{ "oslc:label": "bug 123: server crash", "rdf:resource": "http://example.com/bug123" }]}
Servers MAY include additional server-specific properties in the results JSON.
If the user cancels a dialog, the dialog MUST still send a message with an empty
oslc:results
array.
oslc-response:{"oslc:results": []}
Calls to postMessage
from within a dialog MUST be made on window.opener
unless
null
or undefined
.
If window.opener
is null
or undefined
, calls to
postMessage
MUST be made on window.parent
.
(window.opener || window.parent).postMessage("oslc-response:" + response, "*");
Clients handling message
events from dialogs MUST verify that the event origin
is
the same as the dialog.
For example, if the dialog is from example.com,
function handleMessage(event) { if (event.origin !== "http://example.com") { return; } // Otherwise, process message... }
Dialogs MAY support dynamic resizing as specified in OSLC Resource Preview.
Clients MUST anticipate other, unrelated uses of
postMessage
and ignore unrecognized messages not conforming to the protocol.
Servers MAY support prefill for creation and/or selection dialogs. Client provided prefill information, either in a request entity body or query parameters is intended to inform servers of possible initial values for creation dialogs, or the preferred content of selection dialogs. Clients SHOULD NOT assume any specific content or URL format.
Servers MAY allow clients to prefill dialogs by accepting HTTP POST requests where the Request-URI is the dialog descriptor and the entity body is an entity describing the initial values.
Servers that support prefill MUST include the value
POST
in the set of Allow
header values returned in response to HTTP OPTIONS requests
for the dialog descriptor URI.
Allow: GET,POST,HEAD,OPTIONS
Servers MAY describe prefill constraints by adding an
oslc:resourceShape
property to the dialog descriptor whose value is a
resource shape URI.
Servers MUST NOT reject prefill requests on creation dialogs solely because they are missing required fields for the resource. Users can fill in the missing values in the dialog.
On successful prefill requests, servers MUST respond with status code 201 (Created) and a
Location
header whose value is the URI of the prefilled dialog.
After some elapsed time, servers MAY respond with a 404 (Not Found) or 410 (Gone) to an HTTP GET request for a prefilled dialog URI.
Servers MAY support prefill by adding initial values as query parameters to the delegated dialog URI. Clients SHOULD NOT assume any specific URL format, however.
This document applies the following constraints to the Core vocabulary terms.
An OSLC server providing Dialog capability MUST implement the vocabulary defined in this section.
Dialog results are represented as JSON [[!RFC8259]]. The top-level JSON object has an
oslc:results
property.
Property | Type | Occurs | Description |
---|---|---|---|
oslc:results |
JSON Array | Exactly-one | An array of results, each result a JSON object. An empty array means the user canceled the dialog or didn't select a resource. |
Each result is a JSON object with the following properties.
Property | Type | Occurs | Description |
---|---|---|---|
rdf:resource |
String | Exactly-one | URI of the resource selected or created |
oslc:label |
String | Zero-or-one | Short label describing the resource selected |
Here is an example response that contains two resources.
{ "oslc:results": [ { "oslc:label": "Bug 123: Server crash", "rdf:resource": "http://example.com/bug123" }, { "oslc:label": "Bug 456: Client hangs on startup", "rdf:resource": "http://example.com/bug456" } ] }
When sent as a message in calls to postMessage
, the JSON string is prefixed with the characters
oslc-response:
.