Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal for keyed Access Tokens in a Distributed Network #21

Closed
jricher opened this issue Sep 16, 2019 · 17 comments
Closed

Proposal for keyed Access Tokens in a Distributed Network #21

jricher opened this issue Sep 16, 2019 · 17 comments

Comments

@jricher
Copy link

jricher commented Sep 16, 2019

Public Clients. Instead of dynamic registration as in the current prototype, we should be using static registration or its equivalent to introduce a client to the AS. With the current prototype setup, registration is required to set up a client_id and associate it with the application keys. The downside is that for ephemeral applications, and even native applications that can get deactivated/uninstalled/abandoned, this leaves a lot of dangling registrations at an AS that will never be seen again. The client ID in OAuth2 allows an instance of software to be identified across multiple authorization requests, but it’s rare that a single application instance would ever ask for a second token. I believe that we can use technologies like PKCE and DPoP to fill in the functionality currently provided by DynReg. Coupled with this, we can use a WebID for the client ID, or use it to fetch/validate a client ID, and tie that to a set of display and key information for a client. Client IDs are public information, and any attacker could claim any client ID, but we can use WebID mechanisms to lock down the behavior of a given client ID such that any attacker would need to also have control over the appropriate URLs for an app.

DPoP with ephemeral keys. Instead of the keys being registered in one-time-use client entries, DPoP allows a client to present an ephemeral key at token request time. These keys don’t have to be strongly associated to a client’s identity, but they tie a token request to subsequent token presentations. This prevents a token from being replayed by another party, such as a downstream RS. This key binding lasts as long as the token.

JWT Profile. In addition to the key presentation mechanism of DPoP, we need a way for the RS to figure out who the token’s for and what software is presenting it. We can define JWT claims for the user and client software, and define in the Solid profile that these are WebID’s and how these are to be dereferenced. This would allow the RS to validate the token’s presentation mechanism, which binds to the client, and the token’s own signature, which binds to the AS, and the WebID’s for the user and client, which validate those parties and allow authorization decisions. This JWT access token would replace the use of the ID Token in the current process (and therefore no longer depend on OIDC either), and would need to comply with the various BCP’s for JWTs that are floating around. 1 2 3

Structured Scopes. Proposed work by Torsten Lodderstedt. This allows us to define the kinds of information being requested and authorized by the protocol, and as Dmitry pointed out, the current thinking in the OAuth world aligns with the WAC concepts in Solid.

Alignment with existing infrastructure would take the form of an identity broker (for users on their way in) or an application gateway (for APIs on the way out) to bridge between the Solid ecosystem and traditional OAuth/OIDC/SAML systems.

And finally, much of this approach aligns with ongoing work in the XYZ Project, which is seeking to patch a lot of the problems in the OAuth protocol and its extensions.

@zenomt
Copy link
Contributor

zenomt commented Sep 16, 2019

@jricher regarding Dynamic Registration: today, dynamic registration is used only between a client (such as a single-page browser app (SPA)) and the user's OpenID Provider. since the user is likely to be the same from use-to-use of the same SPA in the same browser on the same device, the SPA can (and many do) remember the client ID & secret (and other aspects of the openid-configuration) from run-to-run in that browser on that device. and as we discussed on the call this morning, my proposal doesn't require a dynamic registration with the Resource Server's Authorization Server either.

regarding DPoP: i believe the DPoP construction specifically is intended to solve a different problem. DPoP as of draft -02 is vulnerable to a downgrade attack, though for Solid it could be mandatory. i think the attack model DPoP is trying to address isn't an issue in Solid (or even in my proposal, as the RS and its AS are already in cahoots, and any auth token presented to an RS would only be good in the same protection spaces controlled by its AS anyway). any proof of possession of a private key that comprises a signature over information required to establish whatever identity/authorization/whatever claims would be sufficient and semantically equivalent (like today's POP tokens, DPoP, HTTP signatures, my proposed POP tokens, etc).

regarding OIDC id_tokens vs a new JWT-based construction: my gut feeling without seeing more specific information is that any new construction would be semantically equivalent to an ID token issued by the user's/webid's trusted identity provider/issuer (for example, an id_token issued by the user's OpenID Connect Provider), but would also require recreating all the rest of the OpenID Connect infrastructure to let the user log in in the first place. i look forward to additional information that might help me understand better what you're proposing.

@elf-pavlik
Copy link
Member

elf-pavlik commented Sep 16, 2019

I think for User associated Authorization Server we don't need Dynamic Registration and actually could use static registration step to let the User set app specific permissions. Having JWT access token to include those app specific authorizations (even just by reference) seems to address use cases where User doesn't want to define it for each Resource Server and does not to have them discoverable except for Resource Servers hosting resources app needs to access.
In cases where multiple Users associate with the same Authorization Server, and some of those users use the same app, would it make sense for each user to register the app oneself? Either way app specfic authorizations would need to apply to the user-app combination not just the app.

@jricher
Copy link
Author

jricher commented Sep 17, 2019

@zenomt: DynReg is needed in WebID-OIDC because the keying material used by the client is associated with the client's registration, and not with the access token itself. This doesn't make sense for ephemeral keys and in-browser clients. This is in fact where DPoP comes into play: the keys used by DPoP do not need to be pre-registered with the client, removing the need to have each instance of the client dynamically register itself with the target AS.

And again my point on ID Tokens: they are never meant to be sent outside of the client, they are a message TO the client. The name "ID Token" is a bad one as it seems to be put on par with, or parallel to, the access token, which is not the case. Access tokens are made to be sent to the RS, which is what we're doing here. What I'm proposing is a method of being able to recognize an access token with a key proof in a distributed fashion, and for that you need at least some means to communicate the token's origins and validity bounds, which is where the JWT comes in.

I don't understand what you mean about "recreating all of the connect infrastructure", because to have the user log in and get the access token, you just need OAuth. Remember, in OIDC, the user isn't logging in to the RS, they're logging in to the client. For the proposal above to work for accessing APIs, you don't need OIDC at all, just OAuth (and the extensions listed). If you want the user's identity information to also be available to the client in a standard fashion, you can also use OIDC on top of OAuth to do that, just as it's designed to do.

And regarding the downgrade attack and token formats: in my view, these would all be required as part of a Solid profile combining all of these technologies. We would not be inventing new endpoints or protocol flows, but we would be combining them in a consistent fashion that we would then standardize.

@zenomt
Copy link
Contributor

zenomt commented Sep 17, 2019

@jricher i think we may be talking past each other. i have a strong feeling that i'm not understanding the access model you're describing and how that fits in with Solid.

... the keys used by DPoP do not need to be pre-registered with the client, removing the need to have each instance of the client dynamically register itself with the target AS.

i'm not sure what you mean by "target AS". in the current Solid POPToken scheme and in my proposal, dynamic registration is only done between the client app and the user's trusted OpenID Provider.

And again my point on ID Tokens: they are never meant to be sent outside of the client, they are a message TO the client.

i understand what you're saying. however, it's not against the rules for a client to show an id_token in its possession to anyone else, particularly if that's what the user wants. while the id_token is audience-bound to the client to which it was sent, having a cnfirmation key in the id_token allows the client to demonstrate to a third party that "the user's trusted OP gave an id_token to somebody, and that somebody is me! so i'm working on behalf of the user, according to the user and her trusted OP".

I don't understand what you mean about "recreating all of the connect infrastructure", because to have the user log in and get the access token, you just need OAuth.

without OIDC, i'm not sure how the user logs in with just OAuth. this and the other things you've described above suggest to me that you're talking about an identity and authorization model very different than WebID-OIDC and Web Access Control, and in particular you're envisioning authorization servers somewhere that issue access tokens that themselves grant access to resources, rather than just conveying the identity of the presenter (and her client app, according to her) where an access control system in the resource server makes a just-in-time access determination based on identity-centric access control rules (for example, WAC). if that's not what you're talking about, then i am very definitely misunderstanding you, for which i apologize (as i don't mean to mischaracterize your proposal).

either way, additional detail to illustrate what all the pieces are and how they fit together would be greatly appreciated.

@dmitrizagidulin
Copy link
Member

Before weighing in, one thing I wanted to clarify:

Currently, the WebID-OIDC protocol does not use the Dynamic Registration to register a client app's keys.
An ephemeral key pair for the client app is generated for each session, and is sent over to the IdP during the Authorization Request step (and returned in the ID Token). (These are the keys that are used for the PoP token etc).

So, currently, we're only using DynReg for a (throwaway) client_id, that's about it.

@elf-pavlik
Copy link
Member

elf-pavlik commented Sep 25, 2019

In DPoP Proof JWTs: Syntax I see:

  • "http_method": The HTTP method for the request to which the JWT is
    attached, as defined in [RFC7231] (REQUIRED).
  • "http_uri": The HTTP URI used for the request, without query and
    fragment parts (REQUIRED).

and later in DPoP Proof JWTs: Checking DPoP Proofs

  1. the "http_uri" claims matches the respective value for the HTTP
    request in which the JWT was received, ignoring any query and
    fragment parts,

Does it mean that if application acting as client and using HTTP/2 wants to fetch contents of LDP Container - let's say containing 1000 LDP Resources - it has to create DPoP Proof JWT for each of those 1000 resources?

I think in current WebID-OIDC application acting as client needs to create just one PoP token per Resource Server. RS would only accept PoP tokens that application created for that RS (@dmitrizagidulin please correct me if I confuse something)


The client ID in OAuth2 allows an instance of software to be identified across multiple authorization requests, but it’s rare that a single application instance would ever ask for a second token. I believe that we can use technologies like PKCE and DPoP to fill in the functionality currently provided by DynReg. Coupled with this, we can use a WebID for the client ID, or use it to fetch/validate a client ID, and tie that to a set of display and key information for a client. Client IDs are public information, and any attacker could claim any client ID, but we can use WebID mechanisms to lock down the behavior of a given client ID such that any attacker would need to also have control over the appropriate URLs for an app.

@jricher Could you please expand on this point. In common example also discussed in solid/authorization-panel#30 (comment) We would have Progressive Web App acting as Public Client served from https://demo.saywhat.example Given that Alice registers this PWA with Authorization Server associated with her and Bob registers the same PWA with Authorization Server associated with him. And that WebID acts as globally unique identifier (IRI). Would both Authorization Servers (Alice's and Bob's) use the same WebID to identify that PWA served from https://demo.saywhat.example or each Authorization Server would create during static registration WebID specific to that AS?

Also would any Authorization Server verify identity of the Application acting as client only based on its redirect_uri ? I understand since we discuss Public Clients we don't use client_secret.

Instead of dynamic registration as in the current prototype, we should be using static registration or its equivalent to introduce a client to the AS.

In case where Public Client (eg. PWA) would use the same WebID with any number of user associated Authorization Servers, what would that static registration result creating?

@jricher
Copy link
Author

jricher commented Sep 25, 2019

To clarify, the client does not create a token. The client :presents: a token with proof of a key associated with that token. So if the client is presenting that token, with its associated proof, to 1000 different RS's, and those RS's are distinct enough from each other that they'd know they were distinct, then yes it would create 1000 different proofs. It does this as part of the process of making the HTTP request. This proof is going to need to be very short-lived in the time scale anyway, and prevent replay attacks with some randomness in the request, so you actually :want: the client to create a new proof each time and not re-use it. If the client reusing a token at multiple RS's over time without additional effort were the goal, we could get by with bearer tokens. But keep in mind if all those resources are in one logical "group", then the client could potentially get away with replaying the same token proof to them, if it did so quickly enough. But then you'd have to weigh the benefits of letting a client do that, sometimes, with the downside of giving an attacker a place in which to easily hide their replay attack.

As for the client_id, it depends on the nature of the app. A web server with shared users wouldn't need to be a public app, for one. An ephemeral SPA style client would be a new instance of the same public client software on every load, even from the same server, and so would therefore need to be either a public client or a dynamically registered client. Same with multiple copies of an installed native application. The static registration would create the client_id, which could in turn be (or be referenced to) a WebID. When talking to multiple AS's, you'd need a way to either register with each of them, or create an identifier that could be referenced by each AS in a distributed fashion. This is one of the downsides of OAuth's model, which assumes a client talks to one AS in the usual mode of operation.

@elf-pavlik
Copy link
Member

Thank you @jricher for quick answer!

In my previous comment I talked about fetching 1000 resources from the same LDP Container so we talk about single Resource Server. If DPoP Proof has REQUIRED http_uri how the same proof could be used to fetch those 1000 resources - let's say all withing 10 seconds? Actually it seems that REQUIRED jti by itself prevents using the same DPoP Proof more than once so even for that 1000 resources in the same LDP Container application would need to create 1000 DPoP Proofs

in DPoP Proof JWTs: Checking DPoP Proofs

  1. that, within a reasonable consideration of accuracy and resource
    utilization, a JWT with the same "jti" value has not been
    received previously (see Section 9.1).

Do you know of any benchmarks of creating DPoP Proofs on average low end mobile device?


JWT Profile. In addition to the key presentation mechanism of DPoP, we need a way for the RS to figure out who the token’s for and what software is presenting it. We can define JWT claims for the user and client software, and define in the Solid profile that these are WebID’s and how these are to be dereferenced. This would allow the RS to validate the token’s presentation mechanism, which binds to the client, and the token’s own signature, which binds to the AS, and the WebID’s for the user and client, which validate those parties and allow authorization decisions. This JWT access token would replace the use of the ID Token in the current process (and therefore no longer depend on OIDC either), and would need to comply with the various BCP’s for JWTs that are floating around. 1 2 3

I would also like to clarify what goes in DPoP-bound Access Token and what goes into DPoP Proof.

  • User's WebID - DPoP-bound Access Token
  • Application's WebID ( =? client_id)- DPoP-bound Access Token
  • access token audience (the RS) - if we follow WebID-OIDC PoP Tokens it would go into DPoP Proof. otherwise application would need to request from Authorization Server a new DPoP-bound Access Toke for each Resource Server it needs to access.

An ephemeral SPA style client would be a new instance of the same public client software on every load, even from the same server, and so would therefore need to be either a public client or a dynamically registered client. Same with multiple copies of an installed native application. The static registration would create the client_id, which could in turn be (or be referenced to) a WebID. When talking to multiple AS's, you'd need a way to either register with each of them, or create an identifier that could be referenced by each AS in a distributed fashion. This is one of the downsides of OAuth's model, which assumes a client talks to one AS in the usual mode of operation.

I think case of SPA/PWA style client comes as very common scenario in Solid ecosystem. If we would require them to have public (global) WebID which includes valid redirect_uri for this application, would that suffice as what you describe in

When talking to multiple AS's, you'd need a way to either register with each of them, or create an identifier that could be referenced by each AS in a distributed fashion. This is one of the downsides of OAuth's model, which assumes a client talks to one AS in the usual mode of operation.

In other words any AS could use that WebID (an IRI) as client_id and not require any AS specific client registration.

@zenomt I recall you mentioning some reason for AS specific client_id, OP specific in case of WebID-OIDC and your implementation which you have mentioned.

@zenomt
Copy link
Contributor

zenomt commented Sep 25, 2019

@elf-pavlik when doing dynamic registration, newly issued client_ids must be unique. on the monday phone call, i mentioned that my OP implementation makes new unique client_ids by encoding information about the registered response types and redirect_uris (and a random salt) directly in the client_id, so no per-client state needs to be stored in the OP. see https://github.com/zenomt/python-webid-oidc/blob/master/oidc.py#L202 which results in a client_id that looks something like

EAgA.arMIccpAhob8OV3vMVYi-dU69P5i.KQDZggTH2LHONFx6

these client_ids also come with client_secrets, also with no per-client state in the OP: https://github.com/zenomt/python-webid-oidc/blob/master/oidc.py#L219 .

the above is one way to do Stateless Dynamic Client Registration.

@elf-pavlik
Copy link
Member

@zenomt do you see any possible problem with all Authorization Servers using globally unique WebID of the application as its client_id? For Public Clients that WebID would only need to include redirect_uri information. For Secure Clients it could have information of Public Key similar as WebID-TLS or WebID-HttpSig proposed in #20. I think with public and global WebID for Applications (clients) used by any Authorization Server, we would never use client_secret and instead rely on asymetric crypto for Secure Clients.

I think that matches this part of the initial proposal

Coupled with this, we can use a WebID for the client ID, or use it to fetch/validate a client ID, and tie that to a set of display and key information for a client. Client IDs are public information, and any attacker could claim any client ID, but we can use WebID mechanisms to lock down the behavior of a given client ID such that any attacker would need to also have control over the appropriate URLs for an app.

For next Monday I'll try to make Sequence diagrams similar to one in https://github.com/solid/webid-oidc-spec/blob/master/application-user-workflow.md based on my understanding of this proposal.

@jricher
Copy link
Author

jricher commented Sep 25, 2019

@elf-pavlik that matches my thinking on the proposal as well. I'm not enough of an expert on WebID, but as long as the AS can recognize the client_id and associate it with the appropriate information, we should be in fine shape.

@zenomt
Copy link
Contributor

zenomt commented Sep 26, 2019

@elf-pavlik

do you see any possible problem with all Authorization Servers using globally unique WebID of the application as its client_id?

i don't see a security problem with this (although since the mapping from webid to redirect_uri is only one-way, the webid of the app isn't strongly authenticated to the user by following the redirect_uri, which might be a problem, and the webid need not have the same origin as the redirect_uri, which might also be a problem; more reflection is needed). however, i do have some other problems with this approach:

currently, WebID-OIDC has a very modest incremental add to an ordinary OpenID Provider:

  1. (required) the webid URI is the sub (or webid if sub can't be used for this) claim of the id_token;
  2. (required for POP tokens) the request parameter for the authorization_endpoint is supported, and the key property of request is inserted into the id_token as the cnf claim;
  3. (required for app identification with POP tokens) the redirect_uri is added to the aud claim of the id_token.

to support "app's webid is the client_id" would require more significant changes to an OpenID Provider:

  1. today an OP can be just a simple receive-requests-only HTTP server (no outbound connections). to support this it would need to make an outbound fetch for the webid document (including TLS PKI validation), and for performance, cache it;
  2. this outbound connection from the OP has security implications, including a potential new attack surface and information leakage;
  3. the OP would need to be able to parse at least Turtle and understand Linked Data to find the webid's hash URI in the document, and the redirect URI triple(s) of the webid -- this is a not-insignificant extra code/complexity footprint in an OP;
  4. the extra code and complexity from (3) can have security audit implications for software that must necessarily be as secure, understandable, and audit-able as possible.

i'd prefer to take a step back and ask what problems we're really trying to solve with this:

  • if it's "dynamic client registration is an extra step", so is fetching the webid document.
  • if it's "the OP will collect tons of single-use clients", if this becomes a problem it can be addressed with stateless dynamic client registration as a server implementation detail with no changes needed to clients.
  • if it's "an app identifier more granular than Origin would be nice", that can be done by using the redirect_uri as the app id (either with dynamic client registration today or by investigating using the redirect URI directly as the client_id as discussed elsewhere (monday's meeting and this comment in gitter) but considering the points above as to whether it's really needed).
  • if it's "it would be super cool if apps were identified by a webid", then i agree, that's pretty cool and could be really useful. however, this would be highly WebID-OIDC specific. WebID-TLS would still be limited to identifying apps by Origin (a least common denominator, and according to TimBL and implied by the Same Origin policy, the only appropriate thing, though i definitely think more granular is useful and appropriate). it's possible future authentication methods might not be able to do better than Origin or redirect URI (especially that it might not be able to establish an app webid). another concern is that the webid might have a different origin than the redirect_uri, which is definitely not in the spirit of the Same Origin Policy.

given the kinds of changes to an OP that would be needed, and the implementation and operational costs associated with them, i'm not in favor of skipping dynamic client registration and using the webid as the client_id. and because i don't believe that DCR is actually a problem, i'm not in favor of skipping DCR and using the redirect_uri as the client_id.

i think there is tremendous value in keeping the required changes to an ordinary OIDC Provider implementation as small and uncontroversial as possible to encourage the adoption and use of WebID-OIDC. all three of today's required additions are backward-compatible and trivial to implement.

@zenomt
Copy link
Contributor

zenomt commented Sep 26, 2019

after writing that giant message above, i thought of a simple example that doesn't work for "app has a webid that the OP dereferences". imagine i'm in my corporate (or home) intranet, using an app hosted on an inside-only server https://someapp.intranet.company.example. the app has a redirect URI of https://someapp.intranet.company.example/static/oauth2.html and a WebID of https://someapp.intranet.company.example/static/card#app. if my OP is outside my intranet, say at https://outside.example/oidc/, it's not going to be able to load https://someapp.intranet.company.example/static/card#app to find the redirect URI(s) or anything else about the app. however, for just the redirect_uri, my OP can redirect because it's my web browser (also inside) that actually looks that up and connects to it.

TL;DR: asymmetric connectivity → no joy.

edit: also consider the "inside-only" server http://localhost:8080 hosting the app/redirect_uri and webid document.

@elf-pavlik
Copy link
Member

imagine i'm in my corporate (or home) intranet, using an app hosted on an inside-only server https://someapp.intranet.company.example. the app has a redirect URI of https://someapp.intranet.company.example/static/oauth2.html and a WebID of https://someapp.intranet.company.example/static/card#app.

Just like with mobile app on the device, redirect_uri doesn't need to be resolvable outside of the device, the WebID does. One could keep app on the intranet but it could still have public WebID. I think in some cases Authorization Server could just use the redirect_uri to identify the client (thinking especially of public clients), still for proper UX AS also usually will need more information about the client than it's redirect_uri. Touching authorization and access control, User might have preference to verify if app has some specific certification possibly represented as Verifiable Credential.

@zenomt
Copy link
Contributor

zenomt commented Sep 29, 2019

@jricher with the benefit of some clarifications in this thread and time for additional reflection, i think i mostly understand what you proposed in the initial posting. i'll address your boldface points here:

Public Clients. Instead of dynamic registration as in the current prototype, we should be using static registration or its equivalent to introduce a client to the AS. With the current prototype setup, registration is required to set up a client_id and associate it with the application keys.

as i mentioned above, i don't believe Dynamic Client Registration is actually a problem that needs to be solved here. i think using a webid (or any other link that must be loaded by the user's identity provider) as an implicit client_id won't work because of asymmetric connectivity. Dynamic Client Registration is not where confirmation keys are registered in the current solution (as @dmitrizagidulin clarified above, that happens at token request time with the authorization_endpoint -- i'm sorry i didn't recognize this misunderstanding earlier). if actual experience shows that DCR is a problem that can't be addressed OP-side with Stateless Dynamic Client Registration, that should be taken up in OIDC.

DPoP with ephemeral keys. Instead of the keys being registered in one-time-use client entries,

the premise here was mistaken: in the current POPToken scheme, ephemeral confirmation keys are associated with the id_token at the authorization_endpoint at get-id_token-time. the id_token's confirmation key is then used to prove possession of the private key to resource servers. i don't think token replay is a concern: in the current POPToken scheme, the POPToken is audience-bound to the RS' origin; in my proposal, the (opaque Bearer) access token you receive from the RS's token endpoint is specific to the protection space/realm on the RS (potentially more specific than origin); in either case, the token isn't useful to other audiences.

JWT Profile. In addition to the key presentation mechanism of DPoP, we need a way for the RS to figure out who the token’s for and what software is presenting it.

an OIDC id_token containing a cnfirmation key addresses this already, requiring only modest additions to an OIDC Provider (adding the cnf key and some kind of app identifier, like the redirect_uri, to the id_token). there's nothing wrong with an app showing this id_token to anyone else and proving control of the private key associated with the cnf. however, requiring all Solid-compatible identity providers to (probably) change the format of their access tokens to be JWTs, and add identity information and a confirmation key (essentially turning them into id tokens) is a much bigger ask. furthermore, while there's nothing wrong with showing someone your id_token, there is potentially something very wrong with showing someone an access token obtained from your OpenID Provider, as that access token might convey actual rights to Resource Servers that are coupled to the OP and that have nothing to do with the Resource Server(s) the app is actually talking to.

Structured Scopes. Proposed work by Torsten Lodderstedt. This allows us to define the kinds of information being requested and authorized by the protocol, and as Dmitry pointed out, the current thinking in the OAuth world aligns with the WAC concepts in Solid.

the user's Identity Provider has no authority to grant an access token for an unassociated (third-party, non-coupled) Resource Server -- all it should have the power to do is to help establish the identity of the presenter. the WAC model places access control decisions in the Resource Server, based on the identity of the client/requestor. scopes of various sorts being added to an identity assertion from an IdP i suppose could be used to reduce the access rights of a presenter to less than those that the RS would otherwise allow, but in all cases access control is ultimately up to the RS.

any statements of scope in any kind of credential/token obtained from the user's identity provider should not improperly leak potentially private information about the user to other parties (for example, if i'm using app Cool Photos, which accesses Alice's photos and Bob's photos, it's not any of Alice's business that i also look at Bob's photos, and it's not any of Bob's business that i look at Alice's photos, and it's neither Alice's nor Bob's business that i use Cool Photos to edit my own photos but only use it to view their photos).

@elf-pavlik
Copy link
Member

the user's Identity Provider has no authority to grant an access token for an unassociated (third-party, non-coupled) Resource Server -- all it should have the power to do is to help establish the identity of the presenter. the WAC model places access control decisions in the Resource Server, based on the identity of the client/requestor.

I think this might apply in current OIDC based approach, I've been looking recently at User-Managed Access (UMA) 2.0 Grant for OAuth 2.0 Authorization and Federated Authorization for User-Managed Access (UMA) 2.0 (both co-authored by @jricher) which provide a lot of flexibility for user to associate resources with authorization servers, quote:

  • The resource owner can control access to resources residing at multiple resource servers from a single authorization server, by virtue of authorizing PAT issuance for each resource server. Any one resource server MAY be operated by a party different from the one operating the authorization server.
  • The resource server defines the boundaries of resources and the scopes available to each resource, and interprets how clients' resource requests map to permission requests, by virtue of being the publisher of the API being protected and using the protection API to communicate to the authorization server.
  • The resource owner works with the authorization server to configure policy conditions (authorization grant rules), which the authorization server executes in the process of issuing access tokens. The authorization process makes use of claims gathered from the requesting party and client in order to satisfy all operative operative policy conditions.

I haven't dived to deep into UMA and I can't tell yet how its use cases compare to solid use cases. For example in Solid w often can have a resource where multiple users have different access modes and they want to use their authorization servers to grant clients of their choice subset of their access.

I think for now we should not assume Resource Server associated Authorization Server and consider User associated Authorization Servers. Possibly based on broad use cases we may need to support both approaches and WAC could provide way for specifying policy for which Authorization Server gets selected for the resource when accessed by a user. In more liberal domains user would use Authorization Server associated with them to delegate access to clients. In more conservative domains, user would have to use Resource Server associated Authorization Server, possibly even using OIDC to authenticate with the AS mandated in that conservative domain.


an OIDC id_token containing a cnfirmation key addresses this already, requiring only modest additions to an OIDC Provider (adding the cnf key and some kind of app identifier, like the redirect_uri, to the id_token). there's nothing wrong with an app showing this id_token to anyone else and proving control of the private key associated with the cnf.

I do think we may have some issues here with audience of the id_token

From https://github.com/solid/webid-oidc-spec#pod

POD

A Personal Online Datastore (POD for short). It plays several roles -- firstly,
it stores a user's data (and so acts as a Resource Server). In many cases, it
also hosts the user's WebID Profile, and implements the API endpoints that allow
it to act as a WebID-OIDC Identity Provider (OP). Lastly, when users requests
resources from it, the POD also acts as a Relying Party (a recipient of those
users' ID Tokens).
In this spec, alice.example and bob.example are both PODs.

And https://github.com/solid/webid-oidc-spec#presenter

Presenter

A public client app that is trying to present a user's credentials from their
home POD to some other POD. For example, Bob is trying to access, via a client
app, a shared file on Alice's alice.example POD, logging in using his own
bob.example POD/provider. In this example, bob.example is a Provider, alice.example is
a Relying Party, and the client app (say, a browser-based HTML editor) is a
Presenter.

I think in usual OIDC the client (app) would act as Relying Party. In current PoP Tokens approach we have pretty much Resource Server (Solid POD) also acting as Relying Party which doesn't get id_token from IdP but gets it from Presenter wrapped in PoP Token.

From https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation

  1. The Client MUST validate that the aud (audience) Claim contains its client_id value registered at the Issuer identified by the iss (issuer) Claim as an audience. The aud (audience) Claim MAY contain an array with more than one element. 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.

https://openid.net/specs/openid-connect-core-1_0.html#Terminology

Relying Party (RP)
OAuth 2.0 Client application requiring End-User Authentication and Claims from an OpenID Provider.

Based on above I don't know if we really can consider Solid POD hosting a resource as OIDC RP.


PROPOSAL: Let's create granular github issues for different aspects we discussed here. Once we clarify the issue we could see how this proposal addresses the specific issue. Currently I think we would have

  • Changes to the PoP Token flow (existing issue)
  • Requirements related to OAuth Client Registration
  • Federated Authorization (Authorization Servers: User associated and Resource Server Associated)

@elf-pavlik
Copy link
Member

I think latest draft submitted by @EndlessTrax follows most aspects of the suggested approach. Structured Scopes / Rich Authorization Requests still need to be evaluated as part of addressing where authorization comes in.
I will close this issue for now and we can always reopen it if needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants