Re: [OAUTH-WG] JWT profile and IdentityServer

Dominick Baier <dbaier@leastprivilege.com> Mon, 04 May 2020 09:00 UTC

Return-Path: <dbaier@leastprivilege.com>
X-Original-To: oauth@ietfa.amsl.com
Delivered-To: oauth@ietfa.amsl.com
Received: from localhost (localhost [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id E3DC33A040A for <oauth@ietfa.amsl.com>; Mon, 4 May 2020 02:00:37 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -1.897
X-Spam-Level:
X-Spam-Status: No, score=-1.897 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, HTML_MESSAGE=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, UNPARSEABLE_RELAY=0.001, URIBL_BLOCKED=0.001] autolearn=ham autolearn_force=no
Authentication-Results: ietfa.amsl.com (amavisd-new); dkim=pass (2048-bit key) header.d=leastprivilege-com.20150623.gappssmtp.com
Received: from mail.ietf.org ([4.31.198.44]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 5JmH517euY5t for <oauth@ietfa.amsl.com>; Mon, 4 May 2020 02:00:35 -0700 (PDT)
Received: from mail-qk1-x734.google.com (mail-qk1-x734.google.com [IPv6:2607:f8b0:4864:20::734]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id 682BB3A0408 for <oauth@ietf.org>; Mon, 4 May 2020 02:00:35 -0700 (PDT)
Received: by mail-qk1-x734.google.com with SMTP id t3so15835543qkg.1 for <oauth@ietf.org>; Mon, 04 May 2020 02:00:35 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=leastprivilege-com.20150623.gappssmtp.com; s=20150623; h=from:in-reply-to:references:mime-version:date:message-id:subject:to; bh=lBWKRScnUf3FVqnlj/7Hr3sB0dVjnViJcXgGYwfqVRc=; b=jF5LjwmDIaZeO+dhCBvgT5DCt36C8noHAeYQUHRSvMMCPt8ec2dcaxJaYQ1TR8rQ76 0HDSSbSH2xpx3CDCg7t56UAikiCg/cqrRjC2ZWasn9ot0M2+W9UPtIR0b/7SnSXc9hlL 5nA5skiT2Z37Fed7vHn4cRecOmonfqSVywOVnTgOdznPBbA4I1ANvhYEYTmLo/1+i/sZ zI/7FP7QfubSVqkNhtYEL9juwJtR6DEot6acUNE0ivNbEBSaYEwPkfw+MxGr8o0HHIb9 xWqaA7jvoGMoDPGUcNaILpxGbe4WoKr8P3qtVVzcCpWo7tm/rYZk72UrWt152IoK/UJ0 jHPA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:in-reply-to:references:mime-version:date :message-id:subject:to; bh=lBWKRScnUf3FVqnlj/7Hr3sB0dVjnViJcXgGYwfqVRc=; b=bjabhlyLHSYJfriK87DQsSd72fE9DlG/3IiBl9eNWbjVkEt+ZL9uqGjt5doUQIClZY O9+qXgaCZBAd3rEAoiOsMNIo4BC6TD2XemKGzsePmItCARydISZltjPkrA8q7ZX63zkN HteUL5LNuh1L5ZgY/a1NfQHPECZS9FRkcasp2pc+M5/sDReBuQg/O96t/y0zRS65BBhC /wq0OPhO6GKH/nQgRMQHluSJr3glNLti4PmFxIzh6A+V6iJEpEjeAj2VYS9t4cafbwHC eQ9ZCZEHVTNundbFFYN7cBHoMWicKYcxMhHiLBNPkgrqkJSKeJTylfYIC8MDYM/JhXQj qOMQ==
X-Gm-Message-State: AGi0PuY2b6Of7iXbmMG2gH2Z0VuC4X21mbRpEp21wDLUNV7u0rRBBgew 57UYoedSKXdFsnmiUqlCihrSNznSz+ozrzo28WIcWSg=
X-Google-Smtp-Source: APiQypLxW8mb6q6ClRpy48bFvlyvbxcFSwB2OX9rUwTKTlCqkdgyYlHe+8y8zGJP91IpPnmLHJ/h8NSlwThUCBD+znw=
X-Received: by 2002:a37:4b4f:: with SMTP id y76mr14792234qka.292.1588582834205; Mon, 04 May 2020 02:00:34 -0700 (PDT)
Received: from 1058052472880 named unknown by gmailapi.google.com with HTTPREST; Mon, 4 May 2020 05:00:33 -0400
From: Dominick Baier <dbaier@leastprivilege.com>
In-Reply-To: <CAO7Ng+vKQpS2o-UhRbSe5fEQv8nR5Qg8rzgsUFo0MdhWjfQ2Yg@mail.gmail.com>
References: <CAO7Ng+vZNsrVb1-Di+7g8_YMXbgns78TaE8uOUR=jX27pbJAoQ@mail.gmail.com> <MWHPR19MB1501DD31A0B6743C680D3382AEA60@MWHPR19MB1501.namprd19.prod.outlook.com> <CAO7Ng+vKQpS2o-UhRbSe5fEQv8nR5Qg8rzgsUFo0MdhWjfQ2Yg@mail.gmail.com>
MIME-Version: 1.0
Date: Mon, 4 May 2020 05:00:33 -0400
Message-ID: <CAO7Ng+vAvPmTs5QNKJVEmbR0SOR70QzYeXoSUTyfht7etqEjCw@mail.gmail.com>
To: Vittorio Bertocci <vittorio.bertocci@auth0.com>, "oauth@ietf.org" <oauth@ietf.org>
Content-Type: multipart/alternative; boundary="00000000000087c90705a4cec355"
Archived-At: <https://mailarchive.ietf.org/arch/msg/oauth/jlDk54-NBGwby8Zb9zSZjxDUhKc>
Subject: Re: [OAUTH-WG] JWT profile and IdentityServer
X-BeenThere: oauth@ietf.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: OAUTH WG <oauth.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/oauth>, <mailto:oauth-request@ietf.org?subject=unsubscribe>
List-Archive: <https://mailarchive.ietf.org/arch/browse/oauth/>
List-Post: <mailto:oauth@ietf.org>
List-Help: <mailto:oauth-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/oauth>, <mailto:oauth-request@ietf.org?subject=subscribe>
X-List-Received-Date: Mon, 04 May 2020 09:00:38 -0000

Oh - and last thing I forgot to mention.

We had the luxury of designing IdentityServer from the ground up after OIDC
has been released. So it really was fine tuned to be a OIDC + OAuth
implementation. Hence the strong semantics of the sub claim for both the
OIDC and OAuth parts. We think this is right because all of our customers
use both in conjunction.

IOW - you move our cheese ;) But don’t worry about it.

———
Dominick Baier

On 4. May 2020 at 10:55:41, Dominick Baier (dbaier@leastprivilege.com)
wrote:

Hey,

No problem - this email was not intended to make you change the document.
Just my conclusions.

OK - let me just set the scene first

* IdentityServer is not a “off the shelf” product or SaaS - it is a
framework. IOW - developers have much greater flexibility and less
constraints to implement custom scenarios. This - as a consequence - allows
doing something “dangerous” - e.g.we cannot enforce how subs or client_id
are generated.

* Every token/identity handling logic in IdentityServer is based on a
simple rule: “if there is a sub - a user is involved, if not - then not”.
Call me old-school - but simplicity wins ;) And this formula has worked
very well for us and our customers. Changing this means we need to re-visit
every place where this logic is applied - so do our customers in both their
STS and resource server implementations. This change is of course doable -
but def. not at this moment in time especially since I am still struggling
if this is the right thing to do or not.

Lastly - I am not sure I understand this comment "not to be enough to
violate 7519”.

The sub claim is OPTIONAL.

https://tools.ietf.org/html/rfc7519#section-4.1.2

And so is aud btw.

So I do not really need to comment on the below scenarios in detail because
they are all a consequence of the above. I could make all these changes,
but they might require a substantial internal change of our logic. So we
decided to not do it. I can only imagine that other STS implementations
come to the same conclusion. And yes I know - you cannot please everybody ;)


Still some comment inline...


thanks
———
Dominick Baier

On 4. May 2020 at 10:20:16, Vittorio Bertocci (vittorio.bertocci@auth0.com)
wrote:

Thank you Dominick, very useful!

I’d like to understand more about the security risks you mention. My goal
is not to change your mind on the implementatio, just to make sure I better
understand the general implication.

*>* the user info endpoint needs to do extra checking*

This is an interesting use case. Often the token issued for the userinfo is
formatless, given that it is colocated within the AS, but I can see how
using JWT for your own userinfo might be useful if you don’t particularly
care about token size or you don’t want to handle an internal token
format/reference.


Could you expand on the security risk? Either the sub doesn’t correspond to
a user, or if it does, the AS itself was the issuer hence it had full
control of whether a sub for a user would end up in a token obtained via
client creds grant… the main way I can see this going south would be if the
developer is allowed to place an arbitrary sub value, but in that case the
issue seem larger (eg in a grant including a user, placing the sub of
another user).


We use the JWT. Sub = user ID. OIDC scopes = what data is returned. This
needs slightly updated logic



*>* extension grants that did not use to present users*

Technically we are still not presenting users- the sub is the authenticated
subject, which can be a user or an app. Here I am channeling the consensus
that was reached after quite a few back and forths, see
https://mailarchive.ietf.org/arch/msg/oauth/F2lLetla0K27W0o2b9oWo0Z8lbM/.

That’s fine - not trying to change your mind



But besides the nitpicking. Could you expand on the extension grants you
are thinking of, and how they’d be affected?

Again our internal extension grant logic is based on the existence of the
sub claim after the response data has been generated. If sub is present we
invoke a whole pipeline around user centric claims. Needs to be changed.



*>* token exchange scenarios*

This is another really interesting point. I admit I haven’t studied the RFC
and I might be remembering an older version, but I believe the specs
referred to principals, which aren’t necessarily human; and I remember one
dev from the community describing a scenario where he would have liked to
be able to do OBO with machine identities, and his scenario was reasonable.

Is there anything specific that breaks in your implementation of token
exchange if you have a sub not corresponding to a user?

See above.





>* enforce a collision domain for sub and client_id

If your product allows developers to arbitrarily set values for one or both
of those, I totally see how enforcement would be extra work! I would argue
that in that case perhaps you don’t have to, if the user can set arbitrary
values they can already do things that would break standards (like
assigning the same sub to two different users) hence in that case you can’t
be responsible for it at product design, it’s kind of up to them.



Note, I know that answering the above might require extra work in
investigating and writing about it, I don’t mean to burden you with it. My
aim here is understanding whether the challenges you identified mostly stem
from the underlying assumption “presence of a sub=>it’s a user”, which is
understandable but was established in the discussions referenced above not
to be enough to violate 7519, or if there are other factors at play that
introduce challenges when sub is used that way.

Thanks again for putting time in checking this and considering implementing
it!

Cheers,

V.



*From: *Dominick Baier <dbaier@leastprivilege.com>
*Date: *Monday, May 4, 2020 at 00:36
*To: *"oauth@ietf.org" <oauth@ietf.org>rg>, "vittorio.bertocci@auth0.com" <
vittorio.bertocci@auth0.com>
*Subject: *JWT profile and IdentityServer



Hey,



Just some notes on applying the JWT profile to IdentityServer



* we emit the at+jwt typ - that’s very useful

* we emit iat in addition to nbf (if we would remove nbf, we would break
the .NET JWT library from Microsoft - I guess that’s the reason AAD emits
it as well)

* we have an option to emit scope as a space delimited string (we used a
string array for historic reasons - also because that’s how the claims
plumbing in .NET prefers it)



* aud



Audience is optional in IdentityServer if you request scopes that do not
have an association to a resource. I personally think this is the right way
to go. You can “force” an audience even for this situation if you
absolutely want to



* sub vs client_id



In IdentityServer access tokens that do not have a user present, do not
have a sub claim - only client_id. If there is a user present, sub ALWAYS
represents the user.



I was prototyping a setting to emit the sub claim for situation where there
is no user, which would not be hard to do - but we found out that there are
many situations where this would need VERY THOROUGH testing of all the
various flows to not introduce subtle security bugs



* the user info endpoint needs to do extra checking

* extension grants that did not use to present users

* token exchange scenarios

* enforce a collision domain for sub and client_id



This could all be sorted probably if I would have enough time right now -
but the bottom line is, that this ambiguity and special casing requires
careful re-writing and I guess this applies to any reasonably complex
system that is already out there. So I am still not sold that the “dual
purpose” claims are the best choice. YMMV.



IOW - we will not adopt the sub/client_id semantics as proposed by the
document.





My 2c / cheers

———

Dominick Baier