webid-oidc-spec icon indicating copy to clipboard operation
webid-oidc-spec copied to clipboard

Proposal: use PoP token issuer (and with that, id token audience) to distinguish web apps

Open michielbdejong opened this issue 6 years ago • 39 comments

I wasn't sure whether to create this issue on this repo or on the WAC repo, but this is a suggestion that came up during the 'acl:trustedApp' session of the unconference we did in Boston on 22 March, and I still had a todo item that I needed to convert it to a github issue. :)

I think the idea that @dmitrizagidulin coined was that instead of identifying web apps by their Origin, we could assign a client_id to web apps when we give them access. I think if it works the same way in OIDC as in OAuth, then that means the pod would maintain a list of whitelisted apps, tying client_id to origin.

@dmitrizagidulin so one thing I'm not clear on now that I'm writing this down, is how would this be different in result, when comparing it to the current system where the pod has a whitelist of origins, rather than of client_id's?

cc @jaxoncreed

michielbdejong avatar Apr 03 '19 09:04 michielbdejong

@michielbdejong

so one thing I'm not clear on now that I'm writing this down, is how would this be different in result, when comparing it to the current system where the pod has a whitelist of origins, rather than of client_id's?

Excellent question. (And just as an added detail, I would advocate that the solid oidc clients actually /use/ the client URLs as client_ids, when registering.)

The main advantage is this: It would extend the "trusted origin" ACL mechanism (and any variations we might come up with), from browser-apps-only, to server side and native apps as well. Meaning, if we treat client_ids as origins, that means all of a sudden, we have greater control over the permissions of service apps, desktop, mobile apps, etc. (As opposed to just assuming they are fully trusted by virtue of not being in the browser, as is the case now.)

dmitrizagidulin avatar Apr 03 '19 15:04 dmitrizagidulin

The main advantage is this: It would extend the "trusted origin" ACL mechanism (and any variations we might come up with), from browser-apps-only, to server side and native apps as well.

For reference - there's a documented example of doing exactly that here

justinwb avatar Apr 03 '19 16:04 justinwb

Briefly discussed on community call. There's preliminary consensus on the developer's side to implement this.

jaxoncreed avatar Apr 04 '19 13:04 jaxoncreed

on the developer's side to implement this.

(to clarify: this should be normative language in the spec too, not just implemented in certain developers' apps/usecases)

gobengo avatar Apr 04 '19 13:04 gobengo

@gobengo Correct. Given the alternative would be inherently insecure, this will now be normative.

jaxoncreed avatar Apr 04 '19 14:04 jaxoncreed

@dmitrizagidulin I just want to confirm that the following is kosher within oidc specs:

Usually, app developers register their app with IDPs. That's where they get their client_id and can set custom redirect urls. But, under Solid, we obviously don't want to require app developers to register with every pod out there, and we certainly don't want apps to be able to redirect just anywhere.

So, after some discussion, the solution I came up with was having a hard restriction in the spec that says all redirect routes MUST be on the same domain as the client_id. Does that sound okay?

jaxoncreed avatar Apr 04 '19 19:04 jaxoncreed

Yeah, I do think that's a reasonable requirement. (Redirect uri to be similar domain as the client_id).

As far as the Dynamic Registration spec, I do vaguely recall that the spec itself points out that the client should feel free to suggest what client_id it wants (meaning, might as well use its uri), but that the IDP would be free to reject it and give it their own.

So yeah, I think it's a decent idea. It's very slightly more restrictive than the current OIDC spec, but in our case, it makes a lot of sense.

dmitrizagidulin avatar Apr 04 '19 21:04 dmitrizagidulin

(And I do like your suggestion that having those two domains be the same means that there's less need for required Dynamic registration.)

dmitrizagidulin avatar Apr 04 '19 21:04 dmitrizagidulin

Usually, app developers register their app with IDPs.

I don't see in this spec explicit mention of OpenID Connect Dynamic Client Registration

Client Registration Response

client_id REQUIRED. Unique Client Identifier. It MUST NOT be currently valid for any other registered Client.

It doesn't seem that client has any influence on how server creates client_id, this spec could mandate specific mechanism for WebID-OIDC

elf-pavlik avatar Apr 04 '19 21:04 elf-pavlik

I think we should consider making it possible to deploy different apps on the same origin. Let's say I would like to only use open source apps and always deploy them on my server. If we don't allow multiple apps (clients) on the same origin I would need to have setup where each app gets its own subdomain.

elf-pavlik avatar Apr 04 '19 21:04 elf-pavlik

@elf-pavlik

It doesn't seem that client has any influence on how server creates client_id

So I think I was thinking of Section 8.2 - Stateless Registration, in the Dynamic Registration spec. I think that one could be interpreted that the client can specify their own client id (if the server is willing)

dmitrizagidulin avatar Apr 04 '19 21:04 dmitrizagidulin

I think we should consider making it possible to deploy different apps on the same origin. Let's say I would like to only use open source apps and always deploy them on my server. If we don't allow multiple apps (clients) on the same origin I would need to have setup where each app gets its own subdomain.

An option to consider that I believe would address this point by @elf-pavlik:

  • client_id is the URL to a WebID associated with that application
  • Provided in the WebID is the redirect_uri to use

justinwb avatar Apr 05 '19 16:04 justinwb

There seems to be a confusion between webapps and automomous apps, in the protocol given, where it says "Upon her confirmation here, DecentPhotos will be added as a trusted application in her WebID Profile, identified by its application/agent WebID (https://decentphotos.example/appid#this), and..." The trusted app system in Alice's profile gives blanket authority to a web app at a particular origin. It only makes sense for web apps, where the Same Origin Policy would normally have the browser block the origin because of webapps being normally untrustworthy. The app's webid should surely just get added to the ACLs for the files, like that of a human agent.

timbl avatar Apr 06 '19 02:04 timbl

The trusted app system in Alice's profile gives blanket authority to a web app at a particular origin. It only makes sense for web apps, where the Same Origin Policy would normally have the browser block the origin because of webapps being normally untrustworthy. The app's webid should surely just get added to the ACLs for the files, like that of a human agent.

Good catch @timbl - you're correct. The intent for that workflow is to demonstrate autonomous apps, which are authorized through the app's webid in the ACLs. Adding to the user's trusted apps in their profile would be unnecessary. Will adjust that.

justinwb avatar Apr 06 '19 02:04 justinwb

There are two distinct proposals being discussed here:

  • Dmitri's proposal, to set the client_id to the app origin. I agree this fixes a problem in the web app flow.
  • the proposal that Justin linked to, to set the client_id to the app agent's webId. I think this is very different from how Solid currently works. Potentially better, I agree, but not a small change that we can decide on here, it would have to be propose for version 0.8 of the Solid spec.

I would vote we go with the first one. At least for now, we can still consider the second one in a few months from now?

michielbdejong avatar Apr 10 '19 18:04 michielbdejong

The second one should be an issue in Solid spec.

RubenVerborgh avatar Apr 10 '19 19:04 RubenVerborgh

For the original proposal, one problem: isn't the client_id specific per app per browser? Meaning that, if I switch browsers or clear local storage, that I have a "new app"? Or is part of this proposal to change that mechanism?

RubenVerborgh avatar Apr 10 '19 19:04 RubenVerborgh

@RubenVerborgh

isn't the client_id specific per app per browser?

Right, so, part of the proposal is to change the mechanism. Currently, each app has no identifier that persists across browser sessions etc - each time, it asks for the IdP to generate a random client_id for it. This works for authentication purposes, but wastes electrons, and is not very helpful for authorization.

So part of the proposal is to have the app propose a client_id to the IdP, during registration. (Or to possibly even consider section 8.2, stateless registration). Specifically, each app would propose its url (which should match the redirect_uri in some way), as the client_id. Which would then be able to be used in the ACL mechanisms.

dmitrizagidulin avatar Apr 10 '19 19:04 dmitrizagidulin

This works, but one, wastes electrons, and is not very helpful :)

Yeah, not to mention create a huge list on the server of one-time IDs that need to be kept just in case, but will never be used.

So part of the proposal is to have the app propose a client_id to the IdP, during registration.

Got it, good.

RubenVerborgh avatar Apr 10 '19 19:04 RubenVerborgh

Great, I think we all agree then. :) Created issues on two implementations of this spec, to follow this new recommendation. We should also edit the spec text to include it.

michielbdejong avatar Apr 11 '19 07:04 michielbdejong

sorry to be late to this thread.

@dmitrizagidulin

So I think I was thinking of Section 8.2 - Stateless Registration, in the Dynamic Registration spec. I think that one could be interpreted that the client can specify their own client id (if the server is willing)

that's not what that section means. 8.2 Implementation Notes on Stateless Dynamic Client Registration says that an authorization server can encode information about the client into the client_id it returns. there's no way for the client to suggest to the server what client_id it would like, and the authorization server should definitely not let the client specify its client_id, because that would destroy a huge aspect of OIDC's security model.

https://github.com/zenomt/python-webid-oidc/blob/master/oidc.py#L199 is the sort of thing Section 8.2 was talking about. that method results in a client ID that looks something like EAEA.Mnf4LyBu24RRpAySC8If3XSYYsvh.FZ_3Y3mZHHDLKY5O. it encodes the requested (and only allowed) response types, hashes of the (only allowed) redirect URIs, and a random salt, so that the client_id is globally unique and can have a client_secret without having to store per-client information in the server.

zenomt avatar Apr 26 '19 03:04 zenomt

@zenomt - you’re absolutely right, thanks for the catch.

I have an alternate proposal, which should accomplish our overall goal, while still being compliant with the spec. (I’ll ask some of the oidc/oauth folks, as well as this community, to review it.)

dmitrizagidulin avatar Apr 26 '19 04:04 dmitrizagidulin

one solution that comes to mind is to extend WebID-OIDC to have another claim in the id_token's claim set: the redirect_uri to which the token (or code) was sent. the redirect_uri claim (or its origin) could be used for access control, for example.

edit the redirect_uri can be added to the audience claim (which can be a list). this requires that the azp claim is present and is the client_id to which the token was actually issued.

one thing i've never been clear on, for the browser-app implicit workflow case: you don't have anything to put in the Authorization: header for some random (not the IdP) server. an id_token is not an access token. the access_token is only meaningful to the IdP and to someone who has the id_token and can compare the access_token to the at_hash claim. perhaps there's some Solid spec i haven't found yet that defines a way to "log in" with an id_token and access_token and get a cookie set or something?

otherwise you need to log in directly to the random server with its normal login page, specify your IdP, and it and your IdP do the OIDC dance.

zenomt avatar Apr 26 '19 04:04 zenomt

i was thinking about my above proposal a lot overnight. while the audience claim seems like the right place to put the redirect_uri, step 3 of 3.1.3.7 ID Token Validation (OIDC Core) is ambiguous and could cause problems. specifically, it says "The ID Token MUST be rejected if the ID Token does not list the Client as a valid audience, or if it contains additional audiences not trusted by the Client." the second clause could mean either "it contains an audience that is not explicitly trusted" or "it contains an audience that is explicitly untrusted". there could be a problem if the redirect_uri is always there for verifying parties that choose the first interpretation.

new proposal: the redirect_uri is added to the aud claims only when the webid scope (or any other scope whose semantics includes this step) is requested by the client.

this still doesn't fully solve the "web app wants to interact with a random server on behalf of the user as their webid" problem though. you want some way to prove to the server that you're acting directly on behalf of the user, and that you're not a MITM that has gotten your hands on an id_token and are presenting it as your own.

i have a sketch of a solution to this second problem. there can be a way to "log in" to the server on behalf of your user (perhaps a new WWW-Authenticate method, or an endpoint discovered via a .well-known URL, or something). the method will include, among other things, a challenge nonce from the server. the app/agent combines this nonce, its own nonce, and the URI or origin or something of the resource it's trying to log in to or access, hashes them all together (perhaps with an HMAC-based construction), and uses that as the nonce to the OIDC server. the returned (signed) id_token will include this nonce. the app/agent then presents the id_token, the challenge nonce, the app/agent nonce, and the URI it thinks it's talking about to the server's login endpoint. the server can look up/verify its nonce to correlate the attempted login session, verify the id_token signature, perform the same hash that the app/agent did to verify the nonce in the id_token, confirm the server URI used refers to it or is allowed, and then apply access controls on the webid and the redirect_uri (or its origin, or whatever it wants). if access is allowed, the server can ~~set a cookie or~~ return an access_token or something.

since the app/agent decides the server URI to include in the nonce it sends to the OIDC server, a third party can't trick the app/agent into giving it an id_token (and other stuff) that the third party could then turn around and use on another server.

update: here's an example exchange illustrating my sketch a little more concretely.

zenomt avatar Apr 26 '19 17:04 zenomt

over the weekend i baked my idea into a complete protocol and wrote up a spec. it addresses app identification for both WebID-OIDC and WebID-TLS, can work with or without any modification to WebID-OIDC, formalizes handling of self-issued OIDC id_tokens, handles the "app/agent accessing resources on random servers on behalf if its user" problem for WebID-OIDC and WebID-TLS, and addresses some of the issues of using WebID-TLS in real life.

i'm happy to submit it in a PR as a proposal, but i'm not sure against which repo or path would be the most appropriate.

@dmitrizagidulin any suggestions?

edit: move link to github this is the full spec, if that will help suggesting an appropriate place to submit properly: WebID HTTP Authorization Protocol

zenomt avatar Apr 29 '19 22:04 zenomt

Hi @zenomt thanks so much for your contribution! I'd like to clarify a few things with you. Would you be open to hopping on a call, or I'll be in the Fremont / Mountainview area next week so we could meet up in person.

jaxoncreed avatar May 02 '19 20:05 jaxoncreed

hi @jaxoncreed . i'm happy to have a call. i made my email address visible in my github profile, so you can email me directly to arrange.

zenomt avatar May 02 '19 20:05 zenomt

i hope i can be excused for not having read all closed tickets in all solid source repos. :) i did find a discussion by @dmitrizagidulin at https://github.com/solid/node-solid-server/issues/1061 which describes exactly the main situation i address in my proposal (IdP/OP, app, and RS are all separate), the discussion including references to PoP tokens (thanks @jaxoncreed for pointing me in that direction when we spoke on the phone).

i haven't yet found documentation on acquiring and using PoP tokens, except for source code.

edit i've read enough of the source that i think i understand how PoP tokens are acquired and would be used in the above 3-party scenario. i have some concerns but they should be made against a spec, not against the source.

i would like to suggest that security protocols (especially) be documented before implementation, both so that the protocol can be examined and vetted by as many security experts as possible, and so that implementations can be audited against the specification to make sure the implementations are correct.

zenomt avatar May 04 '19 20:05 zenomt

Problem this issue aims to solve: https://github.com/solid/webid-oidc-spec/issues/33

RubenVerborgh avatar Jun 16 '19 20:06 RubenVerborgh

In the end we decided that the resource server should look at the issuer of the PoP token. The token validation library will additionally check that is issuer is included in the audience list of the identity token that the PoP token is about.

michielbdejong avatar Jun 17 '19 15:06 michielbdejong