[Jmap] Benjamin Kaduk's Discuss on draft-ietf-jmap-core-14: (with DISCUSS and COMMENT)
Benjamin Kaduk <kaduk@mit.edu> Thu, 21 February 2019 05:27 UTC
Return-Path: <kaduk@mit.edu>
X-Original-To: jmap@ietf.org
Delivered-To: jmap@ietfa.amsl.com
Received: from ietfa.amsl.com (localhost [IPv6:::1]) by ietfa.amsl.com (Postfix) with ESMTP id 0FC7C12D4E6; Wed, 20 Feb 2019 21:27:50 -0800 (PST)
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit
From: Benjamin Kaduk <kaduk@mit.edu>
To: The IESG <iesg@ietf.org>
Cc: draft-ietf-jmap-core@ietf.org, Bron Gondwana <brong@fastmailteam.com>, jmap-chairs@ietf.org, brong@fastmailteam.com, jmap@ietf.org
X-Test-IDTracker: no
X-IETF-IDTracker: 6.91.0
Auto-Submitted: auto-generated
Precedence: bulk
Message-ID: <155072687005.20308.1288342758446844678.idtracker@ietfa.amsl.com>
Date: Wed, 20 Feb 2019 21:27:50 -0800
Archived-At: <https://mailarchive.ietf.org/arch/msg/jmap/NkaQm1nHXIk3Z8GNZyW_hn0kYkA>
Subject: [Jmap] Benjamin Kaduk's Discuss on draft-ietf-jmap-core-14: (with DISCUSS and COMMENT)
X-BeenThere: jmap@ietf.org
X-Mailman-Version: 2.1.29
List-Id: JSON Message Access Protocol <jmap.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/jmap>, <mailto:jmap-request@ietf.org?subject=unsubscribe>
List-Archive: <https://mailarchive.ietf.org/arch/browse/jmap/>
List-Post: <mailto:jmap@ietf.org>
List-Help: <mailto:jmap-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/jmap>, <mailto:jmap-request@ietf.org?subject=subscribe>
X-List-Received-Date: Thu, 21 Feb 2019 05:27:50 -0000
Benjamin Kaduk has entered the following ballot position for draft-ietf-jmap-core-14: Discuss When responding, please keep the subject line intact and reply to all email addresses included in the To and CC lines. (Feel free to cut this introductory paragraph, however.) Please refer to https://www.ietf.org/iesg/statement/discuss-criteria.html for more information about IESG DISCUSS and COMMENT positions. The document, along with other ballot positions, can be found here: https://datatracker.ietf.org/doc/draft-ietf-jmap-core/ ---------------------------------------------------------------------- DISCUSS: ---------------------------------------------------------------------- There's a lot here, and I was not reading in the best of environments, so it's quite possible that I am just confused or missed something while reading. On the whole, this document is well-written and gives me a good picture of how things work. That said, there are still some places where it looks like we may need to have some discussions... This document (twice) has a MUST requirement for HTTP over TLS, which seems to exclude any future usage of HTTP/3 over QUIC. (It's also probably not needed to repeat the normative requirement in two places; I noted both in the COMMENT section.) Section 1.6.2 asserts that "all data belong to a single account". And yet, we seem to have PushSubscription objects in Sections 7.2.1 and 7.2.2 that disclaim any relationship to an account, which seems internally inconsistent. It's also unclear to me from the text in the latter sections what mechanism is used to determine whether a given request is authorized to see a given PushSubscription object. Is it supposed to be based on the authentication credentials to the API service directly, or a user abstraction, or something else? Section 5.3 Some records may hold references to other records (foreign keys). That reference may be set (via create or update) in the same request as the referenced record is created. To do this, the client refers to the new record using its creation id prefixed with a "#". The order of the method calls in the request by the client MUST be such that the record being referenced is created in the same or an earlier call. The server thus never has to look ahead. Instead, while I think this means you need to specify what order the server does the create, update, and destroy lists in -- that is, that all creates are done before all updates, etc.. Section 5.5 The Unicode Collation Algorithm (<http://www.unicode.org/reports/tr10/> is not listed in the IANA collation registry for internet application protocols; since the session object limits the collationAlgorithms to those in the registry, at present, it is not permitted to use that collation algorithm. It would seem that this document should stimulate the registration of that collation algorithm in some fashion (whether by explicitly doing so in its IANA Considerations or otherwise). Section 7.1 o *changed*: "Id[TypeState]" A map of _account id_ to an object encoding the state of data types that have changed for that account since the last StateChange object was pushed, for each of I don't see how these semantics provide the properties stated in Section 7, "[i]t doesn't matter if some push events are dropped before they reach the client; it will still get all changes next time it syncs." In particular, if the client misses a state change for the CalendarEvent type, and then no other changes that affect CalendarEvents occur, the client will remain unaware of the changes to CalendarEvents, even if other push notifications for other types come in. Am I misunderstanding one or more of the behavior or stated guarantees? Section 7.2 As a push subscription causes the JMAP server to make a number of requests to a previously unknown endpoint, it can be used as a vector for launching a denial of service attack. To prevent this, when a subscription is created the JMAP server immediately sends a PushVerification object to that URL (see section 7.2.2). The JMAP server MUST NOT make any further requests to the URL until the client receives the push and updates the subscription with the correct verification code. I think the JMAP server also needs to rate-limit even the initial PushVerification generation, per-user(?), in order to close the DoS and annoyance-vector risks. o *keys*: "Object|null" (immutable) Client-generated encryption keys. If supplied the server MUST use them as specified in [RFC8291] to encrypt all data sent to the push subscription. The object MUST have the following properties: * *p256dh*: the P-256 ECDH Diffie-Hellman public key as described in [RFC8291], encoded in URL-safe Base64 representation as What's the crypto agility story for these web push encryption keys? (See BCP 201.) Also, when these expirations fire (e.g., for Basic Authentication credentials), we need a normative requirement to actually destroy the private credentials; there's a lot going on here so maybe I missed it, but I don't think I saw one. ---------------------------------------------------------------------- COMMENT: ---------------------------------------------------------------------- I also have a big pile of mostly editorial comments. Section 1.1 "Type signatures" sounds a lot like a "JSON Schema". But we can work with what we have, no doubt :) o "String[A]" - A JSON object where the keys are all "String"s, and the values are of type "A". To avoid confusion about whether String is the only possible map key type (vs., e.g., Id), maybe "A[B]" notation is more appropriate? Section 1.2 Do we want to give any guidance about when it is (not) advisable to use very short identifiers (even the 1-2 character case could be noteworthy)? (I don't know what that guidance would be, so "no" is a perfectly fine answer!) W.r.t "NIL", that is the specifc 3-character identifier, right? Or do we need to worry about having it embedded as part of a larger string? (I don't see how prefixing every ID with an alphabetical character avoids the "NIL" case, unless 'N' is disallowed from being that character.) Section 1.3 My math degree obliges me to note that, per trichotomy, zero is not a positive integer. Section 1.6.1 nit: perhaps a "user object", or some broader rewrite like "in this document, the keyword 'user' is used to refer to [...]" -- the current text feels like it's dehumanizing, well, humans. Section 1.6.2 nit re. "All data belong to a single account": I assume this is "each datum has a map to its respective account", not "the entire set of data in the system is associated with a single privileged account", as that would make the account distinction rather useless. Section 1.7 A "MUST" requirement for TLS would seem likely to disallow HTTP/3 (QUIC). Does "MUST confirm with the HTTP Authentication framework" preclude other authentication schemes? The RFC 7235 framework has some warts, and in many webapp settings there are plausible reasons to prefer app-layer authentication schemes. I guess that JMAP as being an API-driven model may have a more natural mapping to the 7235 framework, and I do note the remarks in the shepherd writeup that an authentication scheme was removed from a previous version of this document. So mostly I'm just asking if we are intending to force the 7235 framework to be the one and only authentication scheme for JMAP. (Who knows, maybe this will drive adoption of new HTTP Authentication Schemes or prompt renewed interest in their development?) Clients MUST understand and be able to handle standard HTTP status codes appropriately. (Is there a precise definition for "standard HTTP status codes"?) An authenticated client can fetch the JMAP Session object with details about the data and capabilities the server can provide as nit: maybe this is "a JAMP session object" with the indefinite article? Section 2 o *username*: "String" The username associated with the given credentials. This seems to implicitly require that all credentialed entities have user accounts, denying the possibility for some shared-credential or machine-credential models. Is this intended? o *state*: "String" A string representing the state of this object on the server. If the value of any other property on the session object changes, this string will change. The current value is also returned on the API Response object (see section 3.3), allowing clients to quickly determine if the session information has changed (e.g. an account has been added or removed) and so they need to refetch the object. As written this sounds like a serialized version of the full object (without the 'state' field, of course, to avoid recursion), but I suspect this is intended to be more like a generation number or hash or serialized state, as a short lookup key. Greater clarity would be welcome. (Same comment for all other "state" fields in the document.) In particular, the /changes endpoints seem to place fairly strict bounds on the generation/tracking of *state*. Section 3.2 o *using*: "String[]" The set of capabilities the client wishes to use. The client MAY include capability identifiers even if the method calls it makes do not utilise those capabilities. The server advertises the set of specifications it supports in the JMAP Session object, as keys on the _capabilities_ property. Are the "capability identifiers" the same as or different from the "specifications [the server] supports"? Was there much discussion of short Strings as method names vs. URIs? Is the "client id" something that could also be called a "request ID"? (I note that RFC 7252 calls a similar thing a "token" but has some text wishing they called it a "request ID".) The 'prefixed with a "#"' laguage seems like it has some potential for confusion; is it better to write this like "the first character of the creation ID MUST be octothorpe ('#')"? I'm also still a bit unclear at this point about how the client tells the server which entry in the createdIds map to update when which action completes, but hopefully there is more later. AFAICT having finished reading the doc, these can only be created by explicit client action via a "create" array (or equivalent), where the array keys are the "creation id"s since the client has to use some handle before the server has assigned them. It should be possible to add a very brief note to that effect here. Given the later usage in Section 3.3, I would consider splitting the *Invocation* definition into a subsection. Section 3.3 (editorial) If the second element of the Invocation tuple is literally "arguments for the method", do we really have enough rope to make response objects like this (unless we limit ourselves to conceptually "in/out" arguments with no pure-output functionality)? Section 3.5 I expect that deployment will see differences of opinion as to which checks fall under "syntactically valid", but it's unclear whether we need to attempt to forestall such debate. Section 3.5.1 o "urn:ietf:params:jmap:error:notRequest" The request parsed as JSON but did not match the structure of the Request object. "the Request object" makes me think of "the thing the client stuck in the field named "Request", which is probably not the intent. Perhaps the key phrase is "type signature"? Section 3.5.1.1 Since there is special handling for "urn:ietf:params:jmap:error:limit", do we want an example to show that? Section 3.5.2 With the exception of "serverPartialFail", the externally-visible state of the server MUST NOT have changed if an error is returned at the method level. nit: You don't say where in the type signature "serverPartialFail" is supposed to be in order to trigger the special handling. "invalidArguments": One of the arguments is of the wrong type or otherwise invalid, or a required argument is missing. A "description" property MAY be present to help debug with an explanation of what the problem was. This is a non-localised string, and is not intended to be shown directly to end users. It seems almost certain that it *will* be shown directly to end users, intent or not. But disavowing localization is probably sufficient for now. (et seq.) Further general errors MAY be defined in future RFCs. Should a client receive an error type it does not understand, it MUST treat it the same as the "serverFail" type. Does this imply that "serverPartialFail" is unique in its ability to partially modify state? Section 3.6 (Same comment about '"prefixes with "#"' as above.) If an argument object contains the same argument name in normal and referenced form (e.g. "foo" and "#foo"), the method MUST return an "invalidArguments" error. This "same argument name in normal and referenced form" applies even in arbitrarily nested objects, right? It seems like this could potentially be expensive and/or difficult to enforce. Section 4 I'm trying to consider whether there is any sort of canonicalization or un-escaping behavior that a server might perform on method inputs so that the response would be almost but not exactly the same as the request. (Such behavior could perhaps be used for fingerprinting an implementation.) I can't think of any, though. Section 5.1 o *ids*: "Id[]|null" The ids of the Foo objects to return. If "null" then *all* records of the data type are returned, if this is supported for that data type. Maybe note that the "maxObjectsInGet" capability limit might kick in here for the "null" case? o *properties*: "String[]|null" If supplied, only the properties listed in the array are returned for each Foo object. If "null", all properties of the object are returned. The id property of the object is *always* returned, even if not explicitly requested. If an invalid property is requested, the call MUST be rejected with an "invalidArguments" error. Because we're constrained to a single type here, there's no way for only some (but not all) of the objects to have any given property, right? Section 5.3 o *ifInState*: "String|null" This is a state string as returned by the _Foo/get_ method. If supplied, the string must match the So, just to double-check, this applies to the state of all objects of the type in question (for the account)? It might be worth reiterating, since we frequently see this sort of check against the current state at a per-object granularity, in other systems. Do the "creation id"s in the "create" array include leading "#"? Section 5.4 o *destroyFromIfInState*: "String|null" This argument is passed on as the "ifInState" argument to the implicit _Foo/set_ call, if made at the end of this request. This is "the Implicit _Foo/set_ call that effectuates the destruction of the original", right? o *created*: "Id[Foo]|null" A map of the creation id to an object containing any properties of the copied Foo object that are set by the server (such as the _id_ in most object types). This argument is "null" if no Foo objects were successfully copied. Maybe note that the id property will also likely differ from the one that was passed in in the create array, since the ids in question are from different accounts? Section 5.6 o *upToId*: "Id|null" The last (highest-index) id the client currently has cached from the query results. When there are a Just to double-check: semantically this is an object identifier, but the ordering we care about for the "up to" part is the ordering in the query results? o *removed*: "Id[]" The _id_ for every foo that was in the query results in the old state and is not in the results in the new state. If the server cannot calculate this exactly, the server MAY return extra foos in addition that may have been in the old results but are not in the new results. If the sort and filter are both only on immutable properties and an _upToId_ is supplied and exists in the results, any ids that were removed but have a higher index than _upToId_ SHOULD be omitted. If the _filter_ or _sort_ includes a mutable property, the server MUST include all foos in the current results for which this property MAY have changed. I'm having a hard time understanding this "MAY have changed" text (which, for one, shouldn't be using 2119 language). Taking note that this is the "removed" list, this text seems to be saying that I include in the "removed" list any object that *is* in the current query results, but which may have had a property change since the previous state. So we end up having to do a "remove + add" for this sort of property change, is that right? We may need more detail on the "splices in" operation, with respect to the indices in the "added" array reflecting the final state, and the local cached indices needing to be updated on the fly during the splicing operation in order to get things inserted in the proper places. Section 5.8 2. It must resolve back-references to previous method results that were processed on a different server. This is a relatively simple syntactic substitution, described in section 3.6. Relatively simple, yes, but does require properly parsing the JSON (right?). Section 6.3 Why does Blob/copy use 'blobIds' instead of 'create' like generic /copy? o *fromAccountId*: "Id" The id of the account emails were copied from. o *accountId*: "Id" The id of the account emails were copied to. I assme the "emails" are copy/paste bugs. Section 7.2 o *deviceClientId*: "String" (immutable) An id that uniquely identifies the client + device it is running on. The purpose of this is to allow clients to identify which PushSubscription objects they created even if they lose their local state, so they can revoke or update them. This string MUST be different on different devices, and be different from other vendors. It SHOULD What's the first vendor that's the basis for comparison? be easy to re-generate, not depend on persisted state. A secure hash that includes both a device id and vendor id is one way this could be achieved. Easy to re-generate by whom? How does the client get the deviceClientId value the first time? The POST request MUST have a content type of "application/json" and contain the UTF-8 JSON encoded object as the body. The request MUST (editorial) Are we back to what the JMAP server sends to the notification URL? The push subscription is tied to the credentials used to authenticate the API request that created it. Should these credentials expire or be revoked, the push subscription MUST be destroyed by the JMAP server. How is the JMAP server expected to learn about credential expiry or revocation? When these credentials have their own expiry (i.e. it is a session with a timeout), the server SHOULD NOT set or bound the expiry time (editorial) A session where? Section 7.2.1 I would suggest a section reference to "follows the common /get semantics from Section 5.1, with the exceptions that [...]" to more clearly incorporate by reference the existing text. What nature of authorization checking is done for these get requests? Section 7.2.2 (Same comment about invariants.) Section 7.2.3 Given that all of these times are going to be in the past for all readers, do we want to say something about what time the client is performing these operations at? Section 8.1 Again, this (duplicated!) MUST for TLS prevents future HTTP/3 QUIC usage. Also, please reference RFC 7525. Section 8.2 Please recommend against Basic. SCRAM is probably a tolerable default suggestion; some of the other options that have nicer-looking crypto properties are also not widely deployed, IIUC. Also, the concept of what a "user's regular password" is seems a bit underspecified. Section 8.3 DNS SRV-based autodiscovery seems the only type of autodiscovery available that is susceptible to the attack described here; you should probably just state that explicitly. Section 8.4 While true, 8529's security considerations are pretty sparse; we could say more here about not overscanning, limiting string length, being strict about tokenization, etc. Section 8.7 and JMAP server the client MUST specify encryption keys when establishing the PushSubscription and ignore any push notification received that is not encrypted and signed with those keys. There's no signing in RFC 8291; there is, however, a separate authentication secret. Section 8.8 I would be surprised if the propsects for traffic analysis were limited to just push. Even regular accesses may still be susceptible to traffic analysis. Section 9.4.3 You probably should document that recourse for non-response after 30 days is to request action from the IESG.
- [Jmap] Benjamin Kaduk's Discuss on draft-ietf-jma… Benjamin Kaduk
- Re: [Jmap] Benjamin Kaduk's Discuss on draft-ietf… Alexey Melnikov
- Re: [Jmap] Benjamin Kaduk's Discuss on draft-ietf… Benjamin Kaduk
- Re: [Jmap] Benjamin Kaduk's Discuss on draft-ietf… Alexey Melnikov
- Re: [Jmap] Benjamin Kaduk's Discuss on draft-ietf… Benjamin Kaduk
- Re: [Jmap] Benjamin Kaduk's Discuss on draft-ietf… Neil Jenkins
- Re: [Jmap] Benjamin Kaduk's Discuss on draft-ietf… Benjamin Kaduk
- Re: [Jmap] Benjamin Kaduk's Discuss on draft-ietf… Neil Jenkins
- Re: [Jmap] Benjamin Kaduk's Discuss on draft-ietf… Benjamin Kaduk
- Re: [Jmap] Benjamin Kaduk's Discuss on draft-ietf… Neil Jenkins
- Re: [Jmap] Benjamin Kaduk's Discuss on draft-ietf… Benjamin Kaduk
- Re: [Jmap] Benjamin Kaduk's Discuss on draft-ietf… Benjamin Kaduk
- Re: [Jmap] Benjamin Kaduk's Discuss on draft-ietf… Neil Jenkins
- Re: [Jmap] Benjamin Kaduk's Discuss on draft-ietf… Benjamin Kaduk