dfinity / wg-identity-authentication

Repository of the Identity and Wallet Standards Working Group
https://wiki.internetcomputer.org/wiki/Identity_%26_Authentication
Apache License 2.0
28 stars 9 forks source link

Requirements for Interoperability of Services using User Identity #5

Closed frederikrothenberger closed 1 year ago

frederikrothenberger commented 1 year ago

The working group is currently in the process of gathering requirements for the interoperability topic described here.

To start the discussion about requirements I'd like to propose the following set of requirements:

# Requirement Description Source
R1 Dapps can specify permission sets that can be requested by other (third party) services. The permission sets should consist of the following information:
Metadata
Human readable title and description.
Developers should be able to provide this in multiple languages.
* The description should be able to reference requested values (i.e. “Allow access to account 1234?”).
* Identifier to refer to the given permissions.
Restrictions
Restrictions on canister calls
Allowed functions
Allowed arguments
(multiple) value ranges
Set of values
Single values
Patterns?
** Restrictions on validity
*** Max allowed validity period
 
R2 Permissioned delegations allow a service to access another using the application-specific principal of the other service. Given a user that has delegated some permissions from service B to service A.
Service A will be able to:
access service B using the application-specific principal of service B for actions allowed within the limits set by the granted permissions.
access service B using the application-specific principal of service A with unrestricted permissions (current situation).
 
R3 Permissioned delegations should reveal as little information as possible about the attributes of the user. A service should learn as little information as possible from the permissioned delegation about the user whose permission it received.
(However, this does not prevent services from revealing the user principals themselves.)
 
R4 Once granted, a dapp should not have to request the same permissions again within the validity period of the last delegation. This requires IDPs to keep track of issued delegations. Example:
1. Service A authenticates with IDP → delegation for principal A
2. Service A requests indefinite access to some permissions of Service B
2.a) User grants consent to allow A to access B given the restrictions.
2.b) A does not learn the dapp specific principal of the User on Service B (see R2).
3. User logs out of service A.
4. User logs into service A again.
4.a) The IDP will automatically issue a combined delegation:
4.a)i Delegation for principal A.
4.a)iI Delegation for the dapp specific principal of Service B restricted to the permissions consented to in step 2.
 
R5 Users should be able to list and revoke granted permissions by interacting with the IDP only. The IDP should provide the user with:
A list of all active permissions the user has granted.
Means to revoke the granted permissions. Revocation must take effect within a reasonably short timeframe (e.g. 5 minutes).
 
R6 The replica must enforce the restrictions associated with the granted permissions. Similar to the existing delegations, the replica should validate and check that the current call is allowed given the permissions granted.  
R7 The user consent-flow must be feasible for all combinations of platforms. The flow is feasible for the following participants:
IDPs:
dapp accessed via browser
Browser extension (wallet)
native mobile app (wallet)
Relying parties:
dapp accessed via browser
* native mobile app
 
R8 Permissioned delegations must be robust against changes. If a developer makes changes to a permission set, previously issued consents must become invalid.
This is because users and developers have a different notion which changes to permissions are compatible:
For users, everything that is less permissive is compatible. Permissions cannot be widened because the user has never given consent to the extension.
For developers, everything that is more permissive is compatible. Permissions cannot be removed, because applications might break (i.e. rely on the fact that certain actions are allowed given a specific set of permissions).

The only way to satisfy both points is to make permission sets immutable.
 
R9 Permissioned delegations must be usable by application front-ends as well as canisters. The permissioned delegations should be able to be used for front-end canister calls and inter-canister calls. @Dfinity-Bjoern

Glossary

Please feel free to provide feedback, suggest additions or argue why some requirements should be changed or removed. I'm looking forward to an active discussion. 🙂

Ping: @dostro, @neeboo, @brutoshi

Dfinity-Bjoern commented 1 year ago

Delegation for the dapp specific principal of Service B restricted to the permissions consented to in step 2.

I think this already prescribes one possible implementation and that would be less modular than we could/should go for. I think we should separate between authentication and authorization. The user authenticates with the dapp-specific principal for service A. And then use that together with an authorization for using the services on B under the dapp-specific principal for that service. So the authorization simply wouldn't expire – if the user decides so. I think mixing this into the authentication solution is not a good idea.

Dfinity-Bjoern commented 1 year ago

Users should be able to list and revoke granted permissions by interacting with the IDP only.

I don't think this is a good requirement. Isn't it better to just say that there must be some clearly defined way of listing and revoking the permissions? That's what matters, not where they are.

MioQuispe commented 1 year ago

Since we're talking about interoperability, wouldn't it be worth it to follow existing standards? CACAOs (Chain agnostic capability object) https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-74.md https://github.com/spruceid/cacao-rs and UCANs https://ucan.xyz/ https://github.com/ucan-wg/rs-ucan

Only blocker I can see is they rely on DIDs, but there should exist a DID:icp method anyway. What do you think?

neeboo commented 1 year ago

What really bother us is that caller is the authenticated principal, devs use it to call canister functions. Now if authorization is separated, can we make sure that the authorized principal can be the correct caller?

If it can be done, then NNS-Wallet can reach entrepot to hold NFTs and Tokens of ICPSwaps. For example:

  1. User login to Entrepot, get the Delegation Identity A.
  2. User prompt another window login to NNS or delegate login, get the Delegation Identity B. For UX, we can name it like Authorize Your Wallet or something.
  3. Both Delegation Identity can be verified by same device publickey and signature?

Use B as the caller to call Entrepot minting function and get the NFT

frederikrothenberger commented 1 year ago

Delegation for the dapp specific principal of Service B restricted to the permissions consented to in step 2.

I think this already prescribes one possible implementation and that would be less modular than we could/should go for. I think we should separate between authentication and authorization. The user authenticates with the dapp-specific principal for service A. And then use that together with an authorization for using the services on B under the dapp-specific principal for that service. So the authorization simply wouldn't expire – if the user decides so. I think mixing this into the authentication solution is not a good idea.

Ah, but this would push the responsibility of keeping the authorization credentials around to the dapp, right?

So each dapp would have to build a synchronization layer to share the authorization credentials with other client devices so that a user has to go through the consent process only once. But it would be safe to store the authorization credential in the dapp canister because it can only be used in conjunction with a valid delegation for the matching principal, correct?

frederikrothenberger commented 1 year ago

I don't think this is a good requirement. Isn't it better to just say that there must be some clearly defined way of listing and revoking the permissions? That's what matters, not where they are.

I'm happy to change this requirement to remove the part about interacting with the IDP. However, I think it is important to arrive at a solution, where the user can always revoke a credential regardless of the dapps used (i.e. it should not be possible for revocation to be denied by developers not implementing the corresponding functionality in their dapp). Since there already is a trust relationship between the user and the IDP, revocation at the IDP just seemed to be the most natural solution to me.

frederikrothenberger commented 1 year ago

Since we're talking about interoperability, wouldn't it be worth it to follow existing standards?

Thanks for linking the standards. I think it makes sense to be compatible, unless it requires us to give up features in order to remain compatible. One of the strong points of the IC is that we have the possibility to make capabilities a platform feature, which would relieve all devs from having to validate credentials themselves (which I think would be a huge win).

I have only given it a quick look so far, but UCAN seems more fleshed out than CACAOs.

frederikrothenberger commented 1 year ago

What really bother us is that caller is the authenticated principal, devs use it to call canister functions. Now if authorization is separated, can we make sure that the authorized principal can be the correct caller?

@neeboo: Yes, this is exactly the goal, but with added features such as permission sets, maintaining unlinkability (as far as possible), etc.

MioQuispe commented 1 year ago

Since we're talking about interoperability, wouldn't it be worth it to follow existing standards?

Thanks for linking the standards. I think it makes sense to be compatible, unless it requires us to give up features in order to remain compatible. One of the strong points of the IC is that we have the possibility to make capabilities a platform feature, which would relieve all devs from having to validate credentials themselves (which I think would be a huge win).

I have only given it a quick look so far, but UCAN seems more fleshed out than CACAOs.

Cool. From what Ive gathered CACAOs are based on UCANs but better suited for blockchain use, while UCANs for web2. They aim to be compatible with each other and are working together however.

What would a platform integration look like? Baking them into motoko itself or something more lightweight? Theres a few chains like Flow & Radix that have it as a language feature, though they call it asset oriented programming.

Agoric is the most interesting example of this Ive found https://docs.agoric.com/getting-started/ertp-introduction.html#creating-assets-with-ertp

frederikrothenberger commented 1 year ago

To facilitate further discussions I have create the following PR #6. This should make it easier to comment on specific lines and have parallel discussions.

@MioQuispe:

What would a platform integration look like? Baking them into motoko itself or something more lightweight?

I would hope that we could bake it right into the platform itself. Meaning that a canister call with insufficient permissions will be rejected outright without the canister even being invoked.

If the permissions are sufficient, the platform should resolve the correct principal id automatically:

Given the example from R4, where service A calls service B with

then for canister B caller should resolve to the application specific principal of service B. Service B does not even need to know that the call was made using a permissioned delegation.

dostro commented 1 year ago

I don't think this is a good requirement. Isn't it better to just say that there must be some clearly defined way of listing and revoking the permissions? That's what matters, not where they are.

I'm happy to change this requirement to remove the part about interacting with the IDP. However, I think it is important to arrive at a solution, where the user can always revoke a credential regardless of the dapps used (i.e. it should not be possible for revocation to be denied by developers not implementing the corresponding functionality in their dapp). Since there already is a trust relationship between the user and the IDP, revocation at the IDP just seemed to be the most natural solution to me.

Isn't it important for users to know about their permissions, and how else would they know the permissions they've granted if not in the IDP? In each dapp individually? That sounds difficult to remember and manage.

dostro commented 1 year ago

R5. Revocation must take effect within a reasonably short timeframe (e.g. 5 minutes).

This was an unexpectedly long time -- why so long?

frederikrothenberger commented 1 year ago

Isn't it important for users to know about their permissions, and how else would they know the permissions they've granted if not in the IDP? In each dapp individually? That sounds difficult to remember and manage.

I agree here. But in order to not artificially constrain the solution, interaction with the IDP is not part of the requirement but just one promising solution approach. 😉

frederikrothenberger commented 1 year ago

R5. Revocation must take effect within a reasonably short timeframe (e.g. 5 minutes).

This was an unexpectedly long time -- why so long?

This time gives a hard bound on how long revocation information can be cached, so this is (probably) mainly an efficiency question. Given that revocation is a manual process, I think human time scales make sense.

But this value is absolutely up for debate. What would you have expected?

plitzenberger commented 1 year ago

R.5 Revocation must take effect within a reasonably short timeframe (e.g. 5 minutes).

But this value is absolutely up for debate. What would you have expected?

Shouldn't we have some server side session for being able to revoke the delegation immediately?

frederikrothenberger commented 1 year ago

R.5 Revocation must take effect within a reasonably short timeframe (e.g. 5 minutes).

But this value is absolutely up for debate. What would you have expected?

Shouldn't we have some server side session for being able to revoke the delegation immediately?

I think, it depends on the architecture of the solution. But given that the IC is a distributed system and the component consuming credentials is likely different from the component that handles revocation, I'm not sure immediate revocation is feasible.

At least, I think we should not constrain the solution to immediate revocation as it is a very useful feature even with a short delay.

neeboo commented 1 year ago

R.5 Revocation must take effect within a reasonably short timeframe (e.g. 5 minutes).

But this value is absolutely up for debate. What would you have expected?

Shouldn't we have some server side session for being able to revoke the delegation immediately?

I think, it depends on the architecture of the solution. But given that the IC is a distributed system and the component consuming credentials is likely different from the component that handles revocation, I'm not sure immediate revocation is feasible.

At least, I think we should not constrain the solution to immediate revocation as it is a very useful feature even with a short delay.

What it comes to my mind is that user can see his/her valid and live session (or maybe history in the future?) on II. Whenever he/she wants to terminate that session, he/she just simply login to II and click the terminate button to terminate that session, effective immediately.

alexeychirkov commented 1 year ago

I think that list of valid delegations and method to invalidate delegations should be provided by II canister (rdmx6-jaaaa-aaaaa-aaadq-cai) public interface. This will enable us to work with delegations from different (not https://identity.ic0.app webapp) webapps and even canisters. For a great UX - each delegation could have its creation time and origin ("FrontendHostname").

MioQuispe commented 1 year ago

To facilitate further discussions I have create the following PR #6. This should make it easier to comment on specific lines and have parallel discussions.

@MioQuispe:

What would a platform integration look like? Baking them into motoko itself or something more lightweight?

I would hope that we could bake it right into the platform itself. Meaning that a canister call with insufficient permissions will be rejected outright without the canister even being invoked.

If the permissions are sufficient, the platform should resolve the correct principal id automatically:

Given the example from R4, where service A calls service B with

  • a delegation for the application specific principal of A
  • a credential issued when access to service B (using the application specific principal of B) was granted

then for canister B caller should resolve to the application specific principal of service B. Service B does not even need to know that the call was made using a permissioned delegation.

Would that be compatible with the proposed solutions for inter canister query calls? It seems that relying on caller-id is something that should be avoided https://forum.dfinity.org/t/inter-canister-query-calls-community-consideration/6754/53?u=tbd https://forum.dfinity.org/t/inter-canister-query-calls-community-consideration/6754/57?u=tbd

dostro commented 1 year ago

Isn't it important for users to know about their permissions, and how else would they know the permissions they've granted if not in the IDP? In each dapp individually? That sounds difficult to remember and manage.

We believe a human-readable audit trail of permissions must be part of the requirements:

frederikrothenberger commented 1 year ago

Isn't it important for users to know about their permissions, and how else would they know the permissions they've granted if not in the IDP? In each dapp individually? That sounds difficult to remember and manage.

We believe a human-readable audit trail of permissions must be part of the requirements:

* Which canister did you give permission to

* Which permissions did you grant

* When did you grant them

* Which device granted the permission

* Maybe something about how often this was used by the canister that received permission

* Revoke permission

Reading this list, I'm wondering whether it is actually sensible to mandate this from the IC as a platform. What about rewording it such that the platform must offer interfaces such that an IDP could implement the audit trail & revocation (but making it a responsibility of the IDP to then do so)?

I think this would make the spec here much lighter and shift some weight to canister space which would also make the implementation easier and faster.

domwoe commented 1 year ago

One of the strong points of the IC is that we have the possibility to make capabilities a platform feature, which would relieve all devs from having to validate credentials themselves (which I think would be a huge win).

I agree that capabilities on the platform level would be great, but it is also pretty cool that the IC is powerful enough to allow the implementation of and experimentation with different systems on the application level.

Since we're talking about interoperability, wouldn't it be worth it to follow existing standards?

A few weeks ago I investigated the standards a bit and came across another promising one: Biscuits. You can have a look at the notes of my investigations here. (Note: The teams behind all those standards are very open and approachable)

I'm not sure if it would be a good idea to just take one standard/implementation if we would integrate it on the platform level. This would require quite a lot of changes to the system, but I'm not the right person to evaluate this. But we can definitely learn from them.

Take CACAOs for example. They are conceptually very similar to UCANs, as @MioQuispe already noted, but still, CACAOs have been created because they didn't fit perfectly in the "user signs a human-readable string" model. On the other hand, the simplified CACAO model seems to doesn't allow attenuation, i.e. further restriction of a capability.

From my understanding, Biscuits would be the most powerful approach and I think they are also the most fleshed out. However, it might still be hard to just plug them in the IC, and maybe being inspired by them and taking some parts would be the better choice. On the interoperability point, I think it would be helpful to have a few guiding use cases/scenarios to see if full interoperability would be worth the effort.

If we think about integration capabilities on the platform level, I think it's important to not only think about IDPs and user identities. This is just one use case. We should also have multi-canister architectures in mind. Furthermore, in my personal view, I also like the model of "personal identity providers", i.e. an off-chain wallet or a personal wallet canister that can act as an identity provider. Hence, we should make sure to not only have the Internet Identity glasses on.

frederikrothenberger commented 1 year ago

Tomorrow is the next identity & authentication working group session. Since the requirements do not seem controversial (neither here nor in the PR #6) I'd like to merge the corresponding PR after tomorrows session (pending no further issues raised that would require another iteration). This would move this initiative into the next stage where concrete solutions would be discussed.

Looking forward to tomorrows session.

frederikrothenberger commented 1 year ago

PR #6 has been merged after an additional quiet period of more than 24h as discussed on Nov 1 in the working group session.

I will close this issue now and create separate ones soon for discussions around

New issues regarding the requirements can be created any time if the need arises.

alexeychirkov commented 1 year ago

Hello, are there any news regarding R5?