From b0bada56e102d03a92828da33618103afd99ce24 Mon Sep 17 00:00:00 2001 From: Michiel de Jong Date: Tue, 3 Sep 2024 11:42:03 +0200 Subject: [PATCH 1/6] three files from https://github.com/cs3org/OCM-API/issues/99#issuecomment-2312156700 --- gnap-client-instance-discovery.md | 5 +++ gnap-notifications.md | 11 ++++++ open-cloud-mesh.md | 56 +++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 gnap-client-instance-discovery.md create mode 100644 gnap-notifications.md create mode 100644 open-cloud-mesh.md diff --git a/gnap-client-instance-discovery.md b/gnap-client-instance-discovery.md new file mode 100644 index 0000000..5b02eb3 --- /dev/null +++ b/gnap-client-instance-discovery.md @@ -0,0 +1,5 @@ +For an RO to dynamically register a client instance, they can: +* provide its FQDN +* the AS will retrieve the .well-known +* if this fails, it can do an SRV lookup +* the AS takes a decision whether to dynamically add the client instance or not diff --git a/gnap-notifications.md b/gnap-notifications.md new file mode 100644 index 0000000..9f22033 --- /dev/null +++ b/gnap-notifications.md @@ -0,0 +1,11 @@ +To indicate that a new resource is available for a client instance to access, +an AS can send a notification to that client instance. +This notification may include: +* a displayable description of the resource +* instructions for accessing the resource +* a description of the intended end user, through an identifier or an attribute such as a group name. + +There may be a response notification, accept/reject. + +If the notification is addressed to an unregistered client instance, then the AS MAY dynamically register this client instance +using [GNAP client instance discovery](./gnap-client-instance-discovery.md). diff --git a/open-cloud-mesh.md b/open-cloud-mesh.md new file mode 100644 index 0000000..2bf2a73 --- /dev/null +++ b/open-cloud-mesh.md @@ -0,0 +1,56 @@ +Open Cloud Mesh (OCM) is a server federation protocol that is used in practice in various ways. +This document describes how existing servers implement it. There are three authorization flows: public link, invite, and share with. + +# public link + +Alice creates a public link for a resource on her account on server 1. +Bob visits the GUI of server 1 to view it, and clicks 'save to my cloud '. +Since Bob has access to this resource, he is allowed to tell server 1 to share it forward, so server sends a notification to server 2. +Bob now visits the GUI of server 2 to accept the share there. + +The fact that Bob is allowed to do this means Bob is essentially a resource owner for this resource on server 1. + +So then it's not much different from the share-with flow. + + +The public link flow of OCM was developed independently from GNAP, but is very similar to +the RS-first Method of AS Discovery described in section 9.1 of [GNAP](https://datatracker.ietf.org/doc/draft-ietf-gnap-core-protocol/). + +It can be interpreted as a client instance switching protocol: bob@server1 acts as an RO, registers server2 as a client instance, and grants bob@server2 access. + +# share with + +Share with flow is similar but Alice is the RO who vets and registers server2 as a client instance, and triggers a notification. +It uses a specific implementation of GNAP notifications, and a specific implementation of GNAP client instance discovery in case the +client instance to which the notification is addressed is not (yet) registered at the AS. + +## Details of GNAP notifications +See https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1shares/post + +## Details of GNAP client instance discovery +See https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1ocm-provider/get + +# invite + +Alice sends Bob a nonce out of band. Bob enters this in client instance 2. +It sends a POST to AS 1 with Bob's user identifier. +Client instance registration may happen on the fly. + + +Scenario 1: only pre-trusted receiving servers. +Scenario 2: dynamic client instance registration as part of invite accepting. +Scenario 3: client instance discovery triggered by RO. + +Then GNAP notifications including response notifications + +What to do with resharing? -> permission + +Then legacy: include sharedSecret in the notification. + +show users with access + +public link that doesn't expose the document itself +Like DOI +Request an invite to something + + From 6f9dbe3860a7c96d35b2ef56c2fddd50ae6816a8 Mon Sep 17 00:00:00 2001 From: Michiel de Jong Date: Tue, 3 Sep 2024 11:44:17 +0200 Subject: [PATCH 2/6] Merge other two texts into main doc --- gnap-client-instance-discovery.md | 5 ----- gnap-notifications.md | 11 ----------- open-cloud-mesh.md | 18 ++++++++++++++++++ 3 files changed, 18 insertions(+), 16 deletions(-) delete mode 100644 gnap-client-instance-discovery.md delete mode 100644 gnap-notifications.md diff --git a/gnap-client-instance-discovery.md b/gnap-client-instance-discovery.md deleted file mode 100644 index 5b02eb3..0000000 --- a/gnap-client-instance-discovery.md +++ /dev/null @@ -1,5 +0,0 @@ -For an RO to dynamically register a client instance, they can: -* provide its FQDN -* the AS will retrieve the .well-known -* if this fails, it can do an SRV lookup -* the AS takes a decision whether to dynamically add the client instance or not diff --git a/gnap-notifications.md b/gnap-notifications.md deleted file mode 100644 index 9f22033..0000000 --- a/gnap-notifications.md +++ /dev/null @@ -1,11 +0,0 @@ -To indicate that a new resource is available for a client instance to access, -an AS can send a notification to that client instance. -This notification may include: -* a displayable description of the resource -* instructions for accessing the resource -* a description of the intended end user, through an identifier or an attribute such as a group name. - -There may be a response notification, accept/reject. - -If the notification is addressed to an unregistered client instance, then the AS MAY dynamically register this client instance -using [GNAP client instance discovery](./gnap-client-instance-discovery.md). diff --git a/open-cloud-mesh.md b/open-cloud-mesh.md index 2bf2a73..b4d9ecc 100644 --- a/open-cloud-mesh.md +++ b/open-cloud-mesh.md @@ -25,9 +25,27 @@ It uses a specific implementation of GNAP notifications, and a specific implemen client instance to which the notification is addressed is not (yet) registered at the AS. ## Details of GNAP notifications +To indicate that a new resource is available for a client instance to access, +an AS can send a notification to that client instance. +This notification may include: +* a displayable description of the resource +* instructions for accessing the resource +* a description of the intended end user, through an identifier or an attribute such as a group name. + +There may be a response notification, accept/reject. + +If the notification is addressed to an unregistered client instance, then the AS MAY dynamically register this client instance +using [GNAP client instance discovery](./gnap-client-instance-discovery.md). + See https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1shares/post ## Details of GNAP client instance discovery +For an RO to dynamically register a client instance, they can: +* provide its FQDN +* the AS will retrieve the .well-known +* if this fails, it can do an SRV lookup +* the AS takes a decision whether to dynamically add the client instance or not + See https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1ocm-provider/get # invite From d65c4d21df2b49fd1491b4d1c17b982da5ff4c0e Mon Sep 17 00:00:00 2001 From: Michiel de Jong Date: Tue, 3 Sep 2024 11:46:56 +0200 Subject: [PATCH 3/6] sections from https://github.com/cs3org/OCM-API/issues/99#issuecomment-2326063240 --- open-cloud-mesh.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/open-cloud-mesh.md b/open-cloud-mesh.md index b4d9ecc..4de2830 100644 --- a/open-cloud-mesh.md +++ b/open-cloud-mesh.md @@ -1,7 +1,13 @@ Open Cloud Mesh (OCM) is a server federation protocol that is used in practice in various ways. This document describes how existing servers implement it. There are three authorization flows: public link, invite, and share with. -# public link + +# creating a share, using httpsig+bearer tokens +# other / multiple protocols, extra (legacy) fields +# dynamic client registration, discovery (/.well-known/ocm, /ocm-provider, DNS SRV) +# recipient user/group discovery, invites +# flows +## public link Alice creates a public link for a resource on her account on server 1. Bob visits the GUI of server 1 to view it, and clicks 'save to my cloud '. @@ -18,13 +24,13 @@ the RS-first Method of AS Discovery described in section 9.1 of [GNAP](https://d It can be interpreted as a client instance switching protocol: bob@server1 acts as an RO, registers server2 as a client instance, and grants bob@server2 access. -# share with +## share with Share with flow is similar but Alice is the RO who vets and registers server2 as a client instance, and triggers a notification. It uses a specific implementation of GNAP notifications, and a specific implementation of GNAP client instance discovery in case the client instance to which the notification is addressed is not (yet) registered at the AS. -## Details of GNAP notifications +### Details of GNAP notifications To indicate that a new resource is available for a client instance to access, an AS can send a notification to that client instance. This notification may include: @@ -39,7 +45,7 @@ using [GNAP client instance discovery](./gnap-client-instance-discovery.md). See https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1shares/post -## Details of GNAP client instance discovery +### Details of GNAP client instance discovery For an RO to dynamically register a client instance, they can: * provide its FQDN * the AS will retrieve the .well-known @@ -48,7 +54,7 @@ For an RO to dynamically register a client instance, they can: See https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1ocm-provider/get -# invite +## invite Alice sends Bob a nonce out of band. Bob enters this in client instance 2. It sends a POST to AS 1 with Bob's user identifier. @@ -72,3 +78,5 @@ Like DOI Request an invite to something +# accept/reject/revoke notifications +# reshare notifications \ No newline at end of file From c13684757911c522c8ee5bab217538b87e3cef1b Mon Sep 17 00:00:00 2001 From: Michiel de Jong Date: Tue, 3 Sep 2024 12:15:32 +0200 Subject: [PATCH 4/6] Start with core share creation text, the rest is optional extensions --- open-cloud-mesh.md | 61 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/open-cloud-mesh.md b/open-cloud-mesh.md index 4de2830..9fd0b65 100644 --- a/open-cloud-mesh.md +++ b/open-cloud-mesh.md @@ -1,9 +1,62 @@ -Open Cloud Mesh (OCM) is a server federation protocol that is used in practice in various ways. -This document describes how existing servers implement it. There are three authorization flows: public link, invite, and share with. +Open Cloud Mesh (OCM) is a server federation protocol that is used to notify a remote user that they have +been granted access to some resource. It has similarities with authorization flows such as OAuth, as well as with social fediverse protocols such as ActivityPub. + +# creating a share +Suppose Alice has an account on a sending server (sender.com) and Bob has an account on a receiving server (receiver.com). +The receiving server is registered as an API client of the sending server. +Alice gestures that she wants to grant Bob access to a given resource, and wants him to be notified of this. +In this scenario, support that the sending server knows the OCM endpoint of the receiving server (say `https://receiver.com/ocm`), and also knows some identifier of Bob's account at that server (say `bob-153`). +The sending and receiving server also know each other's public key for http signatures. +To send the notification, the sending server: +* determines the public uri (say `https://sender.com/webdav/some/folder/`) and protocol (say `webdav`) through which the receiving server will be able to access the resource +* generates a unique code, say '123456', +* makes a POST request to the `/shares` path within the receiving server's OCM API, with a JSON body +* includes at least the following fields in that JSON body: +```json +{ + "shareWith": "bob-153@receiver.com", + "protocol": { + "webdav": { + "code": "123456", + "uri": "https://sender.com/webdav/some/folder/" + } + } +} +``` +* generates and adds http signature headers as described in [draft-cavage-http-signatures-12](https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12) + +# obtaining a bearer token +When the receiving server receives ths request, it can obtain a bearer token: +```http +POST /token +Host: sender.com +Content-Type: application/json +[...] + +{ + "client_id": "receiver.com", + "code": "123456" +} +``` +To which the sending server's token endpoint could reply: +```json +{ + "access_token": "asdfghj", + "expires_in": 3600, + "refresh_token": "qwertyuiop" +} +``` +And with that, the receiving server could access the resource at its URI: +```http +GET /webdav/some/folder/ +Host: sender.com +Authorization: Bearer asdfghj +``` + +This completes the description of the basic Open Cloud Mesh mechanism. The rest of this specification details optional extensions and legacy versions of it. - -# creating a share, using httpsig+bearer tokens # other / multiple protocols, extra (legacy) fields + # dynamic client registration, discovery (/.well-known/ocm, /ocm-provider, DNS SRV) # recipient user/group discovery, invites # flows From 546a09c01aacf71bd591530e0490c4dec82ea7b5 Mon Sep 17 00:00:00 2001 From: Michiel de Jong Date: Tue, 3 Sep 2024 14:58:30 +0200 Subject: [PATCH 5/6] more work on the text --- open-cloud-mesh.md | 155 ++++++++++++++++++++++++++++++--------------- 1 file changed, 105 insertions(+), 50 deletions(-) diff --git a/open-cloud-mesh.md b/open-cloud-mesh.md index 9fd0b65..dea320e 100644 --- a/open-cloud-mesh.md +++ b/open-cloud-mesh.md @@ -12,12 +12,17 @@ To send the notification, the sending server: * generates a unique code, say '123456', * makes a POST request to the `/shares` path within the receiving server's OCM API, with a JSON body * includes at least the following fields in that JSON body: -```json +```http +POST /ocm/shares +Host: receiver.com +Content-Type: application/json +[...] + { "shareWith": "bob-153@receiver.com", + "code": "123456", "protocol": { "webdav": { - "code": "123456", "uri": "https://sender.com/webdav/some/folder/" } } @@ -25,13 +30,44 @@ To send the notification, the sending server: ``` * generates and adds http signature headers as described in [draft-cavage-http-signatures-12](https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12) +# share creation request fields +The JSON object in the `/shares` POST body can have the following fields: +* REQUIRED `shareWith` - of the form `@`, where `` SHOULD be a user or group identifier, and `` should be the fully qualified domain name +of the receiving server. +* REQUIRED `code` - SHOULD contain a string that can be exchanged for a short-lived bearer token and refresh token using a signed POST to the sending server's `tokenEndpoint`. See "obtaining a bearer token" below. +* REQUIRED `protocol` - SHOULD have one or more sub-objects, as per the OCM protocol registry (see below). +* OPTIONAL `shareType` - can be omitted, or set to 'user', 'group' or 'federation', to add information to the `` part of the `shareWith` field. +* OPTIONAL `name` - can be used in a notification to the receiving user(s), could be authored by the sender or generated automatically from for instance the file name and path of the resource being shared. +* OPTIONAL `resourceType` - can be for instance 'file' or 'folder', or other types depending on the protocol field. +* OPTIONAL `description` - human-readable string that describes the resource +* OPTIONAL `providerId` - identifier for this share, to be used to refer to it in notifications. Required if notifications are supported. +* OPTIONAL `sharedBy` - an identifier of the form `@` that describes the sending user or origin of this share. +* OPTIONAL `sharedByDisplayName` - a human-readable display name for the sending user or origin of this share. +* OPTIONAL `owner` - an identifier of the form `@` that describes the main authority in control of the resource. +* OPTIONAL `ownerDisplayName` - a human-readable display name for the main authority in control of the resource. + +# OCM protocol registry +## `webdav` +To indicate a resource can be accessed via the WebDAV protocol. It may contain: +* REQUIRED `URI` - URI of the resource. The receiving server SHOULD make sure this URI is on a domain that is under the sending server's control. +* DEPRECATED `sharedSecret` - version 1.1 implementations of OCM expect a long-lived bearer token to be directly included here. This is not recommended. +## `webapp` +[...] +## ... +[...] + # obtaining a bearer token -When the receiving server receives ths request, it can obtain a bearer token: +When the receiving server receives the request, it can obtain a bearer token by making a signed POST request to the `/token` path within the sending server's OCM API, with a JSON body: ```http -POST /token +POST /ocm/token Host: sender.com Content-Type: application/json -[...] +request-target: post /ocm/token +Content-Length: 92 +Host: localhost +Date: Tue, 03 Sep 2024 12:30:03 GMT +Digest: SHA-256=GgoXGmns9ORRxTwHEp8s4UJ6ehjaSQzHgxEbeBFE1is= +Signature: keyId="localhost",algorithm="rsa-sha256",headers="request-target,content-length,host,date,digest",signature="OSGjChaUHiHOfolJLkgdtjDIzeqdcZz42RciNtqaYH4DSifwl+qIoPvB/4ETTGTlizQvyJaPYYVuRWDJ/f+J/nW9FU+ZWahjsyIY/PYHY1ak3IAKUMCf/T/eoS67Tx6DtKCwj5tesN0r6LoMmakYYKNMD/2xM/2Mi8xl4pcPyWcoleRxG7uKsk8CBLahwiYs/OBPe4aJEX6pkdp7iYxTVVxMVOS9gJC/krJGgNx3fwBMPJ22aODRCEMsFnhgSKJPPlsu8hdIGx2A/HTQRI0Ys2Q7MV1Iq+V5vtX2tm9AqxdTxP1AxTHA1Zx38wXKQc5YrneGm4deI1Dph1/k95JyIQ==" { "client_id": "receiver.com", @@ -41,7 +77,8 @@ Content-Type: application/json To which the sending server's token endpoint could reply: ```json { - "access_token": "asdfghj", + "access_token": "asdfgh", + "token_type": "bearer", "expires_in": 3600, "refresh_token": "qwertyuiop" } @@ -50,15 +87,70 @@ And with that, the receiving server could access the resource at its URI: ```http GET /webdav/some/folder/ Host: sender.com -Authorization: Bearer asdfghj +Authorization: Bearer asdfgh ``` This completes the description of the basic Open Cloud Mesh mechanism. The rest of this specification details optional extensions and legacy versions of it. -# other / multiple protocols, extra (legacy) fields +# legacy resource access +In OCM version 1.1, for the webdav protocol, the resource could be accessed using a WebDAV request to the URI specified in `protocol.webdav.URI`, adding +an `Authorization: Bearer ` or `Authorization: Bearer ` header. +In OCM version 1.0, for the webdav protocol, the resource could be accessed using a WebDAV request a previously agreed URI, adding +an `Authorization: Basic ` header. +The `protocol.webdav.sharedSecret` and `protocol.options.sharedSecret` fields SHOULD NOT be included in a share creation request unless the receiving server +is known to support only older versions of OCM. +When received, they SHOULD NOT be used unless the sending server is known to support only older versions of OCM. + +# dynamic client registration +Although OCM is useful in a closed community such as a continent-wide network of universities that mutually trust each other, it can also be used in open mode, +more like email or social networking, where a sending server is allowed to send an OCM share to ANY receiving server that understands it. + +To enable this, the sending server needs to: +* discover information about the receiving server, either from a directory or by doing server config discovery (see below) + +### server config discovery +From a fully qualified domain name, the sending and receiving servers could discover information about each other by fetching +`https:///.well-known/ocm` or (if that fails) `https:///ocm-provider`. If that also fails, they could try a DNS SRV +lookup of `_ocm._tcp.` which could then for instance resolve to `service = 10 10 443 `, after which discovery +could be reattempted using `` instead of ``. + +The resulting configuration document can contain the following fields: +* REQUIRED `apiVersion` - SHOULD be one of `"1.0-proposal1"`, `"1.1.0"` or `"2.0"` +* REQUIRED `endPoint` - this was used instead as the base URL for all OCM requests like create-share, token, etc. +* OPTIONAL `capabilities` - array of strings indicating which capabilities this OCM server has. Example: `[ '/invite-accepted' ]` +* OPTIONAL `federation` - see https://github.com/cs3org/OCM-API/pull/94 +* OPTIONAL `resourceTypes` - array of resource type objects, each with: +* OPTIONAL `resourceTypes[i].name` - string describing the type, for instance `"file"` +* OPTIONAL `resourceTypes[i].shareTypes` - array of strings describing the share types supported for this resource type, for instance `["user", "federated"]` +* OPTIONAL `resourceTypes[i].protocols` - object containing protocol API base URLs for various protocols +* OPTIONAL `provider` - a human-readable name for this server -# dynamic client registration, discovery (/.well-known/ocm, /ocm-provider, DNS SRV) # recipient user/group discovery, invites +The receiving server MAY expose a directory service for the sending server to discover potential recipient users and (federated) groups. +The servers MAY also share a directory service such as a community-administered Authorization and Authentication Infrastructure of which +both servers are a member, and where (federated) group information or user identifiers can be looked up. + +## invites +Servers MAY also support the `/invite-accepted` capability, and if both the sending and the receiving server do, and both servers trust each other, +then the invite flow may be used to bootstrap common knowledge of user identifiers between the participating users. If supported, this optional capability of OCM servers +works as follows. + +### send a unique string +Say Alice wants to initiate a connection with Bob, with the goal of discovering Bob's user identifier and OCM server, and at the same time sending her own user identifier and OCM server +information to Bob. Using an out-of-band communication channel (for instance email or voice), she shares a unique string with Bob. Bob passes this string on to his OCM server in some way. +This might involve opening a URL at a redirect server and finding his OCM server in a list, copy-pasting the string into a graphical user interface, scanning a QR code with a smartphone application, etcetera. + +### server-to-server information exchange + +The string contains the fully qualified domain name of Alice's OCM server, so Bob's server can use server config discovery (see above) to contact Alice's server. It can then make an `invite-accepted` +request to it (see [example](https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1notifications/post)), sharing a unique user identifier for Bob. +Alice's server can respond and include a unique user identifier for Alice in the reply. + +### contacts interface + +Next time Alice wants to share a resource with Bob, she will not have to input Bob's full user identifier and OCM server FQDN into her OCM server's interface. Instead, she will be able to select Bob +from a list of contacts, and initiate the sharing from there. + # flows ## public link @@ -83,53 +175,16 @@ Share with flow is similar but Alice is the RO who vets and registers server2 as It uses a specific implementation of GNAP notifications, and a specific implementation of GNAP client instance discovery in case the client instance to which the notification is addressed is not (yet) registered at the AS. -### Details of GNAP notifications -To indicate that a new resource is available for a client instance to access, -an AS can send a notification to that client instance. -This notification may include: -* a displayable description of the resource -* instructions for accessing the resource -* a description of the intended end user, through an identifier or an attribute such as a group name. - -There may be a response notification, accept/reject. - -If the notification is addressed to an unregistered client instance, then the AS MAY dynamically register this client instance -using [GNAP client instance discovery](./gnap-client-instance-discovery.md). - -See https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1shares/post - -### Details of GNAP client instance discovery -For an RO to dynamically register a client instance, they can: -* provide its FQDN -* the AS will retrieve the .well-known -* if this fails, it can do an SRV lookup -* the AS takes a decision whether to dynamically add the client instance or not - -See https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1ocm-provider/get - -## invite - -Alice sends Bob a nonce out of band. Bob enters this in client instance 2. -It sends a POST to AS 1 with Bob's user identifier. Client instance registration may happen on the fly. - Scenario 1: only pre-trusted receiving servers. Scenario 2: dynamic client instance registration as part of invite accepting. Scenario 3: client instance discovery triggered by RO. -Then GNAP notifications including response notifications - -What to do with resharing? -> permission - -Then legacy: include sharedSecret in the notification. - -show users with access +# accept/reject/revoke notifications +# reshare notifications -public link that doesn't expose the document itself +# show users with access +# public link that doesn't expose the document itself Like DOI Request an invite to something - - -# accept/reject/revoke notifications -# reshare notifications \ No newline at end of file From 8c1824713cdc740d7834274db8c0a739cc0352d6 Mon Sep 17 00:00:00 2001 From: Michiel de Jong Date: Tue, 3 Sep 2024 16:09:58 +0200 Subject: [PATCH 6/6] restructure the document --- open-cloud-mesh.md | 226 ++++++++++++++++++++++++++------------------- 1 file changed, 132 insertions(+), 94 deletions(-) diff --git a/open-cloud-mesh.md b/open-cloud-mesh.md index dea320e..90872ce 100644 --- a/open-cloud-mesh.md +++ b/open-cloud-mesh.md @@ -1,11 +1,109 @@ Open Cloud Mesh (OCM) is a server federation protocol that is used to notify a remote user that they have -been granted access to some resource. It has similarities with authorization flows such as OAuth, as well as with social fediverse protocols such as ActivityPub. +been granted access to some resource. It has similarities with authorization flows such as OAuth, as well as with social internet protocols such as ActivityPub and email. -# creating a share +# Establishing recipient details +An OCM share creation may start in various ways. Here is a non-exhaustive list of examples. The initiation ends with the sending server +knowing the receiving user id and OCM FQDN. + +## share with +In the simplest case, the sending user types in the receiving user or group id and the OCM FQDN. They may also select it from a list of contacts. +The OCM FQDN the user can choose MAY be restricted to ones the sending server already trusts. +The receiving user or group id the user can choose MAY be restricted to ones the user has established contact with using out-of-band invite codes. + +The receiving server MAY expose a directory service for the sending server to discover potential recipient users and (federated) groups. +The servers MAY also share a directory service such as a community-administered Authorization and Authentication Infrastructure of which +both servers are a member, and where (federated) group information or user identifiers can be looked up. + +## invites + +If Alice (alice at sender.com) and Bob (bob at receiver.com) know each other, yet they may not have a mechanism to trust any received share request, as that may be similar to receiving spam. + +In this case, Alice may invite Bob to initiate a mutual trust relationship: on the provider side, the sender.com service MAY implement an interface for Alice to generate a single-use token and send it to Bob off-band (e.g. via e-mail). In addition, the sender.com service MAY integrate this interface with ScienceMesh, and only allow a curated white list of sites as receivers. + +On the receiving end, assuming that Bob wishes to accept the invitation, the receiving server MAY provide an interface for Bob to input the received token, or to interact with the ScienceMesh directory. In any case, the receiving server SHOULD make a HTTP POST request to the /invite-accepted endpoint of the sending server, sending the token and disclosing Bob's identity details such as bob at receiver.com. If the token matches the one created earlier by Alice, the response MUST include Alice's identity details such as alice at sender.com. + +Following this step, both services at sender.com and receiver.com MAY display, respectively, bob and alice as trusted or white-listed contacts, and enable sharing between them. Sites MAY enforce a policy to only accept shares between such trusted contacts, or MAY display a warning to users when a share from an unknown party is received. + +For further details on this concept, see also #54 and related issues. For a discussion about trust policies, see sciencemesh#196. + +Servers MAY also support the `/invite-accepted` capability, and if both the sending and the receiving server do, and both servers trust each other, +then the invite flow may be used to bootstrap common knowledge of user identifiers between the participating users. If supported, this optional capability of OCM servers +works as follows. + +### send a unique string +Say Alice wants to initiate a connection with Bob, with the goal of discovering Bob's user identifier and OCM server, and at the same time sending her own user identifier and OCM server +information to Bob. Using an out-of-band communication channel (for instance email or voice), she shares a unique string with Bob. Bob passes this string on to his OCM server in some way. +This might involve opening a URL at a redirect server and finding his OCM server in a list, copy-pasting the string into a graphical user interface, scanning a QR code with a smartphone application, etcetera. + +### server-to-server information exchange + +The string contains the fully qualified domain name of Alice's OCM server, so Bob's server can use server config discovery (see above) to contact Alice's server. It can then make an `invite-accepted` +request to it (see [example](https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1notifications/post)), sharing a unique user identifier for Bob. +Alice's server can respond and include a unique user identifier for Alice in the reply. + +### contacts interface + +Next time Alice wants to share a resource with Bob, she will not have to input Bob's full user identifier and OCM server FQDN into her OCM server's interface. Instead, she will be able to select Bob +from a list of contacts, and initiate the sharing from there. + +## share with +It uses a specific implementation of GNAP notifications, and a specific implementation of GNAP client instance discovery in case the +client instance to which the notification is addressed is not (yet) registered at the AS. + +## public link to resource +In another scenario, Alice creates a public link for a resource on her account on server 1. +Bob visits the GUI of server 1 to view it, and clicks 'save to my cloud '. +Since Bob has access to this resource, he is allowed to tell server 1 to share it forward, so server sends a notification to server 2. +Bob now visits the GUI of server 2 to accept the share there. + +The fact that Bob is allowed to do this means Bob is essentially a resource owner for this resource on server 1. + +So then it's not much different from the share-with flow. + +It can be interpreted as a client instance switching protocol: bob@server1 acts as an RO, registers server2 as a client instance, and grants bob@server2 access. + +## public link to invite +Likewise, Alice could create a public link that doesn't expose the document, but just allows people to send access requests to it by entering their OCM address. + +# Decision to send +In the share-with flow, the sender is (in OAUth terms) the Resource Owner who vets and registers the receiving server as a client instance, and triggers a notification. + +Client instance registration may happen on the fly. + +Scenario 1: only pre-trusted receiving servers. +Scenario 2: dynamic client instance registration as part of invite accepting. +Scenario 3: client instance discovery triggered by RO. + +## dynamic client registration +Although OCM is useful in a closed community such as a continent-wide network of universities that mutually trust each other, it can also be used in open mode, +more like email or social networking, where a sending server is allowed to send an OCM share to ANY receiving server that understands it. + +To enable this, the sending server needs to: +* discover information about the receiving server, either from a directory or by doing server config discovery (see below) + +## server config discovery +From a fully qualified domain name, the sending and receiving servers could discover information about each other by fetching +`https:///.well-known/ocm` or (if that fails) `https:///ocm-provider`. If that also fails, they could try a DNS SRV +lookup of `_ocm._tcp.` which could then for instance resolve to `service = 10 10 443 `, after which discovery +could be reattempted using `` instead of ``. + +The resulting configuration document can contain the following fields: +* REQUIRED `apiVersion` - SHOULD be one of `"1.0-proposal1"`, `"1.1.0"` or `"2.0"` +* REQUIRED `endPoint` - this was used instead as the base URL for all OCM requests like create-share, token, etc. +* OPTIONAL `capabilities` - array of strings indicating which capabilities this OCM server has. Example: `[ '/invite-accepted' ]` +* OPTIONAL `federation` - see https://github.com/cs3org/OCM-API/pull/94 +* OPTIONAL `resourceTypes` - array of resource type objects, each with: +* OPTIONAL `resourceTypes[i].name` - string describing the type, for instance `"file"` +* OPTIONAL `resourceTypes[i].shareTypes` - array of strings describing the share types supported for this resource type, for instance `["user", "federated"]` +* OPTIONAL `resourceTypes[i].protocols` - object containing protocol API base URLs for various protocols +* OPTIONAL `provider` - a human-readable name for this server + + +# Notification of share creation Suppose Alice has an account on a sending server (sender.com) and Bob has an account on a receiving server (receiver.com). -The receiving server is registered as an API client of the sending server. +The receiving server is registered as an API client of the sending server, or it MAY be registered dynamically as part of the process. Alice gestures that she wants to grant Bob access to a given resource, and wants him to be notified of this. -In this scenario, support that the sending server knows the OCM endpoint of the receiving server (say `https://receiver.com/ocm`), and also knows some identifier of Bob's account at that server (say `bob-153`). +In this scenario, suppose that the sending server knows the OCM endpoint of the receiving server (say `https://receiver.com/ocm`), and also knows some identifier of Bob's account at that server (say `bob-153`). The sending and receiving server also know each other's public key for http signatures. To send the notification, the sending server: * determines the public uri (say `https://sender.com/webdav/some/folder/`) and protocol (say `webdav`) through which the receiving server will be able to access the resource @@ -30,7 +128,7 @@ Content-Type: application/json ``` * generates and adds http signature headers as described in [draft-cavage-http-signatures-12](https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12) -# share creation request fields +## share creation request fields The JSON object in the `/shares` POST body can have the following fields: * REQUIRED `shareWith` - of the form `@`, where `` SHOULD be a user or group identifier, and `` should be the fully qualified domain name of the receiving server. @@ -46,17 +144,28 @@ of the receiving server. * OPTIONAL `owner` - an identifier of the form `@` that describes the main authority in control of the resource. * OPTIONAL `ownerDisplayName` - a human-readable display name for the main authority in control of the resource. -# OCM protocol registry -## `webdav` +## OCM protocol registry +### `webdav` To indicate a resource can be accessed via the WebDAV protocol. It may contain: * REQUIRED `URI` - URI of the resource. The receiving server SHOULD make sure this URI is on a domain that is under the sending server's control. * DEPRECATED `sharedSecret` - version 1.1 implementations of OCM expect a long-lived bearer token to be directly included here. This is not recommended. -## `webapp` +### `webapp` [...] -## ... +### ... [...] -# obtaining a bearer token +# Decision to receive +The share creation notification SHOULD be signed using httpsig. The receiving server MAY reject any incoming notifications from servers it doesn't explicitly trust, +or from OCM addresses who didn't go through the invite flow with the listed recipient OCM address. + +# Notification of acceptance/rejection +The receiving server MAY respond with a [notification](https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1notifications/post) of type `"SHARE_ACCEPTED"` +or `"SHARE_DECLINED"`. + +This information MAY be shown to the sending user and/or to the administrator of the sending server. +If this information is shown, a revoke button MAY be presented alongside. + +# Obtaining the access token When the receiving server receives the request, it can obtain a bearer token by making a signed POST request to the `/token` path within the sending server's OCM API, with a JSON body: ```http POST /ocm/token @@ -83,7 +192,9 @@ To which the sending server's token endpoint could reply: "refresh_token": "qwertyuiop" } ``` -And with that, the receiving server could access the resource at its URI: + +# Accessing the resource +With the `access_token` from the previous section, the receiving server could access the resource at its URI: ```http GET /webdav/some/folder/ Host: sender.com @@ -92,7 +203,7 @@ Authorization: Bearer asdfgh This completes the description of the basic Open Cloud Mesh mechanism. The rest of this specification details optional extensions and legacy versions of it. -# legacy resource access +## sharedSecret-based resource access In OCM version 1.1, for the webdav protocol, the resource could be accessed using a WebDAV request to the URI specified in `protocol.webdav.URI`, adding an `Authorization: Bearer ` or `Authorization: Bearer ` header. In OCM version 1.0, for the webdav protocol, the resource could be accessed using a WebDAV request a previously agreed URI, adding @@ -101,90 +212,17 @@ The `protocol.webdav.sharedSecret` and `protocol.options.sharedSecret` fields SH is known to support only older versions of OCM. When received, they SHOULD NOT be used unless the sending server is known to support only older versions of OCM. -# dynamic client registration -Although OCM is useful in a closed community such as a continent-wide network of universities that mutually trust each other, it can also be used in open mode, -more like email or social networking, where a sending server is allowed to send an OCM share to ANY receiving server that understands it. - -To enable this, the sending server needs to: -* discover information about the receiving server, either from a directory or by doing server config discovery (see below) - -### server config discovery -From a fully qualified domain name, the sending and receiving servers could discover information about each other by fetching -`https:///.well-known/ocm` or (if that fails) `https:///ocm-provider`. If that also fails, they could try a DNS SRV -lookup of `_ocm._tcp.` which could then for instance resolve to `service = 10 10 443 `, after which discovery -could be reattempted using `` instead of ``. - -The resulting configuration document can contain the following fields: -* REQUIRED `apiVersion` - SHOULD be one of `"1.0-proposal1"`, `"1.1.0"` or `"2.0"` -* REQUIRED `endPoint` - this was used instead as the base URL for all OCM requests like create-share, token, etc. -* OPTIONAL `capabilities` - array of strings indicating which capabilities this OCM server has. Example: `[ '/invite-accepted' ]` -* OPTIONAL `federation` - see https://github.com/cs3org/OCM-API/pull/94 -* OPTIONAL `resourceTypes` - array of resource type objects, each with: -* OPTIONAL `resourceTypes[i].name` - string describing the type, for instance `"file"` -* OPTIONAL `resourceTypes[i].shareTypes` - array of strings describing the share types supported for this resource type, for instance `["user", "federated"]` -* OPTIONAL `resourceTypes[i].protocols` - object containing protocol API base URLs for various protocols -* OPTIONAL `provider` - a human-readable name for this server +## Multi Factor Authentication +If an OCM provider exposes the capability /mfa-capable, it indicates that it will try and comply with a MFA requirement set as a permission on a share. If the sharer OCM provider trusts the receiver OCM provider, the sharer MAY set the permission mfa-enforced on a share, which SHOULD be honored. A compliant OCM provider that signals that it is MFA-capable MUST not allow access to a resource protected with the mfa-enforced permission, if the consumer has not provided a second factor to establish their identity with greater confidence. -# recipient user/group discovery, invites -The receiving server MAY expose a directory service for the sending server to discover potential recipient users and (federated) groups. -The servers MAY also share a directory service such as a community-administered Authorization and Authentication Infrastructure of which -both servers are a member, and where (federated) group information or user identifiers can be looked up. +Since there is no way to guarantee that the sharee OCM provider will actually enforce the MFA requirement, it is up to the sharer OCM provider to establish a trust with the OCM sharee provider such that it is reasonable to assume that the sharee OCM provider will honor the MFA requirement. This establishment of trust will inevitably be implementation dependent, and can be done for example using a pre approved allow list of trusted OCM providers. The procedure of establishing trust is out of scope for this specification: a mechanism similar to the ScienceMesh integration for the Invite capability may be envisaged. -## invites -Servers MAY also support the `/invite-accepted` capability, and if both the sending and the receiving server do, and both servers trust each other, -then the invite flow may be used to bootstrap common knowledge of user identifiers between the participating users. If supported, this optional capability of OCM servers -works as follows. +# Share Deletion +A "SHARE_ACCEPTED" notification followed by a "SHARE_UNSHARED" notification is equivalent to a "SHARE_DECLINED" notification. -### send a unique string -Say Alice wants to initiate a connection with Bob, with the goal of discovering Bob's user identifier and OCM server, and at the same time sending her own user identifier and OCM server -information to Bob. Using an out-of-band communication channel (for instance email or voice), she shares a unique string with Bob. Bob passes this string on to his OCM server in some way. -This might involve opening a URL at a redirect server and finding his OCM server in a list, copy-pasting the string into a graphical user interface, scanning a QR code with a smartphone application, etcetera. - -### server-to-server information exchange - -The string contains the fully qualified domain name of Alice's OCM server, so Bob's server can use server config discovery (see above) to contact Alice's server. It can then make an `invite-accepted` -request to it (see [example](https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1notifications/post)), sharing a unique user identifier for Bob. -Alice's server can respond and include a unique user identifier for Alice in the reply. - -### contacts interface - -Next time Alice wants to share a resource with Bob, she will not have to input Bob's full user identifier and OCM server FQDN into her OCM server's interface. Instead, she will be able to select Bob -from a list of contacts, and initiate the sharing from there. - -# flows -## public link - -Alice creates a public link for a resource on her account on server 1. -Bob visits the GUI of server 1 to view it, and clicks 'save to my cloud '. -Since Bob has access to this resource, he is allowed to tell server 1 to share it forward, so server sends a notification to server 2. -Bob now visits the GUI of server 2 to accept the share there. - -The fact that Bob is allowed to do this means Bob is essentially a resource owner for this resource on server 1. - -So then it's not much different from the share-with flow. - - -The public link flow of OCM was developed independently from GNAP, but is very similar to -the RS-first Method of AS Discovery described in section 9.1 of [GNAP](https://datatracker.ietf.org/doc/draft-ietf-gnap-core-protocol/). - -It can be interpreted as a client instance switching protocol: bob@server1 acts as an RO, registers server2 as a client instance, and grants bob@server2 access. - -## share with - -Share with flow is similar but Alice is the RO who vets and registers server2 as a client instance, and triggers a notification. -It uses a specific implementation of GNAP notifications, and a specific implementation of GNAP client instance discovery in case the -client instance to which the notification is addressed is not (yet) registered at the AS. - -Client instance registration may happen on the fly. - -Scenario 1: only pre-trusted receiving servers. -Scenario 2: dynamic client instance registration as part of invite accepting. -Scenario 3: client instance discovery triggered by RO. +# Share Updating +TODO: document "RESHARE_CHANGE_PERMISSION" -# accept/reject/revoke notifications -# reshare notifications +# Resharing the resource +The "REQUEST_RESHARE" and "RESHARE_UNDO" notification types MAY be used by the receiving server to persuarde the sending server to share the same resource with another share recipient. TODO: document how receiver.com can know if sender.com understood and processed the reshare request. -# show users with access -# public link that doesn't expose the document itself -Like DOI -Request an invite to something