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

AuthAccount capabilities #53

Merged
merged 7 commits into from
Mar 22, 2023
Merged

Conversation

turbolent
Copy link
Member

No description provided.

@turbolent turbolent requested a review from a team December 7, 2022 23:31
@turbolent turbolent requested review from dete and a team December 7, 2022 23:32
Copy link
Member

@joshuahannan joshuahannan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems fine to me. Is there a way to restrict access to the AuthAccount capability in this FLIP, or will that be somewhere else. I mean like potentially only allowing the capability to access certain paths or something like that

cadence/2022-12-07-authaccount-capabilities.md Outdated Show resolved Hide resolved
Comment on lines +42 to +43
This proposal suggests adding a very powerful feature: An account capability allows full access to the account,
i.e. full access to manage storage, keys, contracts, etc.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think a nice supplement to this feature would a few "interface" supertypes defined for AuthAccount to slightly mitigate this drawback. If we could create/publish a capability to a StorageWriter that only has access to link and save, or a ContractUpdater that can only add/remove contracts, it would be slightly safer to give someone access to this capability so they can, say, save a new value to your storage without also allowing them to remove all your contracts.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, I had proposed this before and still would like to see such interfaces being added to the language, maybe as a separate proposal though, as they would also be useful without account capabilities.

@bluesign
Copy link
Collaborator

bluesign commented Dec 9, 2022

I link my previous comments here : onflow/cadence#2151

I think this is very dangerous capability. Also if we call passing AuthAccount an anti-pattern, I don't know how to justify this.

@dete
Copy link

dete commented Dec 9, 2022

@bluesign: I completely understand your concerns, but the more I think about it, the less I see how this opens up new attack vectors. If I'm an attacker, I can ask you to sign a transaction that adds my key to your account just as easily as I can ask you to sign a transaction that gives me a copy of your AuthAccount capability. All of the examples of security holes you gave in the other thread can be implemented, today, via keys.

Of course, that doesn't mean that both aren't a big problem! It underscores the need to get to widespread Flix adoption by wallets, so we can get to the point where wallets can reject (or at least, warn users about) all non-Flix transactions as potentially malicious.

I'm very much excited about the added security we can get from the proper use of this functionality. So, I'm looking forward to seeing this go live.

@bluesign
Copy link
Collaborator

bluesign commented Dec 9, 2022

@dete I agree Flix will help on this for sure.

Maybe I missed some use case, but what is the planned use case for this that, we cannot do with capabilities today? I mean in the other thread answer was; capabilities are complicated, error prone, prone to security issues, cumbersome etc.

To be honest for me one of the best part of Cadence is Capabilities, maybe I am a bit too much defensive on the issue because of that :)

@jacob-tucker
Copy link

jacob-tucker commented Dec 10, 2022

Hello, agreeing with @bluesign here, it is obvious that this is very dangerous. I understand @dete’s point that it doesn’t necessarily introduce any further vulnerabilities because technically I could trick someone into signing a malicious transaction all the same now, but either way, this does open up many more doors for trickery.

My main concern here is that there is no detailed reasoning for why this is needed. What are the use cases for such a feature? Saying it will indirectly benefit a user is not strong enough imo.

@bjartek
Copy link
Contributor

bjartek commented Dec 10, 2022

Jumping in a little late here. I question why there is a flip when it is already implemented?

As the flip says this can already be implemented in userland so I do not see the need. Am I messing something?

If you somehow add a key you can atleast see what key did something. With this it is hard to spot.

@austinkline
Copy link
Contributor

austinkline commented Dec 10, 2022

I've got a lot of concern here, and for a few reasons.

First is the proposed feature itself. There is little detail in here to me to make such a big shift in what's allowed and what flow itself encourages justifiable. We're talking about permitting the direct linking of AuthAccounts. Can we get example usage, how we might prevent bad behavior, and context to where this came from? For this flip to say that the engineering work is already done suggests that the decision to add this was made prior to community engagement. @bluesign linked a prior ticket with a little bit of back and forth, but their concerns were not addressed there, and not here either in my opinion.

Secondly, there are no guardrails. Just like conversations we've had about Providers for FTs and NFTs and their all-or-nothing nature, this flip proposes perpetuating that very issue but in a much bigger and more dangerous way. Some folks in comments have asked about the possibility of limiting the scope of this kind of link in some way, but we've already had some discussion about that very topic which I myself brought up a while ago here but there's no mention of system like that in this flip despite the flip being approved. If cadence is going to encourage linking AuthAccounts by making it a first-class feature, we should absolutely be baking proper access control and scoping into it, which is why reading that no more effort is needed to ship this is so concerning. To me, there are absolutely more pieces of this to sort out before it could be made a bonafide part of the language.

Thirdly, @dete can you give more detail about how this makes flow more secure? Again, speaking about being ready for this to go live raises concerns that the decision is done here so maybe we're wasting our breath. But we should definitely be shooting for more protections in the event of accidental linking issues like with Matrix Market just a few weeks ago, malicious updates in the event that a contract bakes this kind of use into its functionality, or disgruntled employees who could compromise entire pieces of the network if they get access to the controlling wallet depending on how this gets used.

In its current form, I do not think there is enough information to accept this FLIP, and would strongly encourage another round of discussion with the community in addition to what has already been done.

@LanfordCai
Copy link

LanfordCai commented Dec 12, 2022

I actually think that we should not only have limitations on the AuthAccount capability mentioned in this FLIP, but also the AuthAccount itself. It's a bit easy for an attacker to do fishing and steal the whole user account now.

FLIX is good, but a low level limitation would be better.

@dsainati1
Copy link
Contributor

Just wanted to jump in to to reply regarding the fact that this FLIP is "already implemented". I can understand why it might seem like proposing a FLIP with the solution already implemented would imply that the decision has already been made, but this is not the case, nor is it out of the ordinary at all. We very often implement FLIPs during or prior to the proposal process, not because we expect them to be accepted immediately (or because we have decided in advance what to do), but because we want to be sure that the FLIPs are actually implementable as proposed. Cadence's implementation is complex, and there are often subtleties to features that may complicate the design that are difficult to predict in advance. In order to be sure that we won't hit some issue during the implementation of a FLIP whose design has been accepted, we often implement the proposed design (either in full, or partially as a prototype) to make sure the proposed solution is tractable.

This has been the case for many FLIPs already, including those that have either been rejected or dramatically changed over the course of their discussion process. The recently accepted attachments feature, for example, had an implementation when it was still "extensions" that ended up being unused because the design it followed was rejected and the feature was changed.

@bluesign
Copy link
Collaborator

bluesign commented Dec 12, 2022

@dsainati1 I have the tendency to misunderstand but is there any other case like this one? This is on next spork, and behind feature flag. Neither default implementations nor borrowContract case was like this?

Btw this even didn't start as FLIP, this started as implementation, then I commented and asked that this has to be FLIP ( not sure if it was gonna be FLIP or not, but I believe what @turbolent says )

But the main issue is, even FLIP is sub par, not sure whose idea it is (FLIP owner is @turbolent, I personally disappointed to see his name but it is offtopic) Idea and use case is not in the FLIP (linked PR discussion explained a bit )

But we can get some lessons from this ( in the positive side )

  • Maybe we shouldn't merge stuff till FLIP is approved.
  • Maybe we can involve more people in FLIPs ( especially business people can be involved a bit more, as probably they are the smartest minds behind those )
  • We can make longer and more extensive FLIPs
  • Brainstorming sessions can involve community and we don't see the PR first.

Anyway safe to say this didn't get community approval, what is the next step ? do we rollback the PR ? Maybe we start a working group for this ?

@bluesign
Copy link
Collaborator

bluesign commented Dec 12, 2022

@dsainati1 This is not the case here, as you can see with links below, I have high respect for all of you but when I see comments like yours, I feel it is not mutual, and it hurts.

I mean if you don't know about things below and commented that I apologize, if you know and commented this as off-topic, this steers conversation and sends another message ( like it is not decided ) which is disrespectful.

https://www.notion.so/dapperlabs/Child-accounts-000903ca581946a3b8ff861daab64f5f

Support Sub Accounts in a Developer Wallet #1499
onflow/fcl-js#1499

Epic to track work on child accounts.
onflow/cadence#2192

PS: btw you have all the rights to say that we decided and will do like this, this is your choice. But if you say, no we will develop with community, this doesn't seem like this

PS: can't see the notion ofc, but someone can be kind and share, I appriciate

@dsainati1
Copy link
Contributor

@bluesign none of these things necessarily imply that this FLIP has already been decided on. onflow/flow#739 is a great example of a past FLIP that had internal support from the team (in particular Dete) and issue opened for it and track work on it (onflow/cadence#1322). However, when we proposed this to the community, the response was negative and the FLIP was not accepted.

@katelynsills
Copy link

Would it be possible to get more information on the particular use cases? Ideally, we'd want to make sure the authority that we're handing over is the least amount of authority to do the job (POLA). And if we have particular use cases in mind, we can tell which authority needs to be packaged together, and which can be left out.

I think this FLIP should only be accepted after common patterns for reducing authority are also implemented and understood by the community, otherwise it seems likely to encourage disastrous patterns.

These discussions seemed helpful towards that goal:

From @dsainati1:

I still think a nice supplement to this feature would a few "interface" supertypes defined for AuthAccount to slightly mitigate this drawback. If we could create/publish a capability to a StorageWriter that only has access to link and save, or a ContractUpdater that can only add/remove contracts, it would be slightly safer to give someone access to this capability so they can, say, save a new value to your storage without also allowing them to remove all your contracts.

From @austinkline:

I suggest we devise a protection mechanism to wrap AuthAccount types to control what a consumer of an AuthAccount can do, making it safe(er) to pass around. This ScopedAuthAccount would be given permission to access/modify only specific paths of the AuthAccount. With a mechanism like that, we could start to encourage NFT collections to create a setup method that takes this ScopedAuthAccount and configures it exactly as it is supposed to be. This puts the setup responsibility on creators of each resource to enumerate how they should be setup, taking the heavy-lifting away from dapps who have to make guesses on what to configure and what types to expose.

@katelynsills
Copy link

Additionally, it seems like one of the major reasons for this FLIP is so that every account doesn't need to deploy a contract to delegate access to their AuthAccount. What's the main issue with this? Is it storage space (thousands of identical contracts being deployed)? If so, it seems like there might be alternatives that haven't yet been discussed.

@turbolent
Copy link
Member Author

turbolent commented Dec 15, 2022

Thank you everyone for your great feedback, it is much appreciated! 🙏

It took me a a while to write up this response, thank you all for your patience.

Though I am the author of this proposal and implementator of the feature in Cadence, I was only asked to author it on behalf of the group who requested the feature. The proposal only includes the Cadence feature, as this was the extent of my knowledge. I will try to transfer authorship of this FLIP to that group, which can hopefully drive this proposal and provide the remaining detail.

There have been a lot of comments and I could identify several categories/topics of feedback:

Restrictions / "Guard rails"

@joshuahannan:

Is there a way to restrict access to the AuthAccount capability in this FLIP, [...] like potentially only allowing the capability to access certain paths or something like that

@dsainati1:

[...] a nice supplement to this feature would a few "interface" supertypes defined for AuthAccount to slightly mitigate this drawback.

@austinkline

If cadence is going to encourage linking AuthAccounts by making it a first-class feature, we should absolutely be baking proper access control and scoping into it, which is why reading that no more effort is needed to ship this is so concerning.

@katelynsills

Ideally, we'd want to make sure the authority that we're handing over is the least amount of authority to do the job (POLA).

The proposal does not currently propose any such access restriction functionality. I have personally advocated for such language additions for a while, though not yet through a concrete proposal. For example, like @dsainati1 described, we could define interfaces for AuthAccount and its subtypes, like AuthAccount.Keys, which could be used in restricted references.

Such functionality would also be useful without account capabilities, for example to statically restrict access to signing accounts of a transaction: Imaging a transaction with e.g.

transaction {
  prepare(signer: &AuthAccount{AccountBorrow}) {
    signer.load(/* ... */) // static error: not available due to restriction
  }
}

Where AccountBorrow is defined as something like:

/// AccountBorrow allows access to the borrow function of an AuthAccount
struct interface AccountBorrow {
  fun borrow(/* ... */)
}

Because such functionality would also be useful outside of the account capabilities feature, and to keep this proposal small, I think it is better to propose such functionality in a separate proposal. This FLIP should maybe then depend on that a FLIP.

Once such restrictions / "guard rails" exist, they should be used where necessary, and usage should be strongly encouraged.

Still, having full access to another account is useful, so it will not be possible to require the use of access restrictions for account links. Please see the use-case section below.

Note that the FLIP mentioning that "no more [implementation] effort is needed" is purely in regards to what the proposal currently proposes – an implementation of what is currently proposed is available.
That does not imply that the proposal should be extended with additional functionality, which then of course needs to be implemented, i.e. requires more implementation effort.

Safety

@bluesign

I think this is very dangerous capability. Also if we call passing AuthAccount an anti-pattern, I don't know how to justify this.

@austinkline

[...] there are no guardrails.
[...], this flip proposes perpetuating that very issue but in a much bigger and more dangerous way.

Like @dete pointed out, this feature does not add any additional attack vectors: Account capabilities can be implemented today using a contract.

As with all features, there is a trade-off between functionality and safety.

This feature is very powerful and it should be treated as such. It should definitely only be used in certain cases. I agree that adding "guard rails" will help with preventing usage in unsafe ways.

The utility of the feature is not immediately apparent, which brings me to the next point –
once the use-case is explained, it should be easier to evaluate if the proposed feature should be added, in terms of the trade-off between functionality and safety.

Use case / Context

@bluesign

Maybe I missed some use case, but what is the planned use case for this that, we cannot do with capabilities today?

@jacob-tucker

[...] there is no detailed reasoning for why this is needed. What are the use cases for such a feature? Saying it will indirectly benefit a user is not strong enough imo.

@austinkline

There is little detail in here to me to make such a big shift in what's allowed and what flow itself encourages justifiable. We're talking about permitting the direct linking of AuthAccounts. Can we get example usage, how we might prevent bad behavior, and context to where this came from?

@bluesign

Maybe we can involve more people in FLIPs ( especially business people can be involved a bit more, as probably they are the smartest minds behind those)

@katelynsills

Would it be possible to get more information on the particular use cases?

Missing use-case(s) and context is clearly the biggest shortcoming of this FLIP, I totally agree and apologize for the lack. They are essential to justify the utility of the feature.

When writing the FLIP I mainly focused on the technical details: The feature is simple, it is a single function; also, it is merely "sugar": it integrates a pattern into the language which is already implementable through a contract, today.

I underestimated the importance of demonstrating how adding the feature to the language is justified, by describing use-case(s) and providing example(s).

The group proposing the feature, lead by @dete, is trying to solve several problems and has put a lot of thought into the issue and solutions.

A description from @dete:

One of the biggest problems with Web3 is requiring folks to have a wallet before on-boarding.
Unfortunately, if you just use Web2 account management techniques, everybody's NFTs end up in app-managed blockchain accounts.
The whole point of Web3 is interoperability and portability, and app-managed blockchain accounts don't allow that to happen.
Previously, the best solution for easy on-boarding uses app-managed blockchain accounts, and then ask users to transfer their assets OUT of the application to use them in other experiences; this is annoying at the least, and potentially very confusing (if the user forgets which of their accounts their assets are in).

Child accounts allow users to sign up for new experiences using standard Web2 account management, and then, when they are ready for all of the features of Web3, they can attach a wallet as a parent account and have full access to all of their assets in all of their applications.
As a bonus, this mechanism allows for applications to manage the assets in their "domain" without having to incessantly ask for signing permission, while keeping all of the assets outside their "domain" secure, but accessible by asking for permission.

The group is currently in the process of writing and plans to publish a more detailed document, but needs a bit more time to explain their thinking - stay tuned.

Lesson learned: We wanted to get feedback as early as possible, but should have waited until we have a good description of the big-picture problem(s), not when a description of the technical solution is ready.

Implementation

@bjartek

I question why there is a flip when it is already implemented?

As the flip says this can already be implemented in userland so I do not see the need. Am I messing something?

@bluesign

This is on next spork, and behind feature flag.

[...] Btw this even didn't start as FLIP, this started as implementation, [...]

[...] Maybe we shouldn't merge stuff till FLIP is approved.

Like @dsainati1 explained, only the status of the FLIP matters, not the status of an implementation of it. The existence of an implementation has no implications on the decision on a FLIP.

Though an implementation for a FLIP is not necessary, it is actually really helpful to have an implementation available:

  • It enables reviewers of the FLIP to evaluate the proposed functionality and allows them to validate that the proposal solves the problems it is meant to solve.
  • In addition, it ensures the technical feasibility of the proposal.

Some projects even require an implementation for a proposal, exactly for the reasons described above, for example, Swift's proposal process.

Ideally, FLIPs should always come with an implementation. In some cases, like for this FLIP, this is very easy. In other cases, like in the past e.g. for the Cadence attachments feature, this was very difficult. Still, even there, an implementation was developed in parallel.

I can only emphasize what Daniel explained above: An implementation does neither exist because we expect the proposal to be accepted immediately, nor because we already decided in advance that it should be accepted.

Also, an implementation existing in the codebase does not imply that it is available, will be available in the next spork, etc.

The fact that an implementation exists in the codebase is purely a technical detail: There are different ways how an implementation of a feature can be made available for evaluation.

One way is to have a feature branch, which keeps the code separate from the main branch. We have used this approach for complex features, like for attachments.

However, this results in a significant organizational overhead: The branch needs to be kept in sync with the main branch, downstream dependencies (like flow-go, Emulator, CLI, many more) need equivalent feature branches, etc.

For smaller features, like what is suggested in this proposal, it is much easier to use feature flagging: The feature is in the main codebase, but disabled by default. This allows us to easily provide e.g. a single version of the Flow Emulator and CLI where a user can choose to enable the feature to evaluate it.
This is a very common approach and used in most other language projects, too. For example, the Swift compiler ships with -enable-<feature-name> CLI flags which enable certain experimental features.

The Cadence team will continue to choose an appropriate/practical way to make an implementation available to the community. In any case the approach has no relevancy in the review process.

I am currently working on preparing a preview build of the Flow CLI which includes this feature (along with attachments) and will announce it here as soon as it is ready.

The Flow Smart Contract Engineering team is very eager to get their hands on the preview build to evaluate the feature. They also plan to build a demo dapp which demonstrates how the feature can be used to solve the problems described above, i.e. provide a great user experience for dapps.

As the proposed feature for Cadence is just a part of a much bigger solution, other components (like FCL) need to have support for it as well. We use GitHub issues to coordinate the implementation and integration network. Again, the existence of issues does not imply that the functionality described in the issues will end up in Flow.

The Cadence team's (just like the Flow team's) goal is to engage with the community in making decisions, and we provide implementations to assist reviewers, not to ignore the community! 🙂

It is unfortunate that it is seen in a different way, I really hope this response clarifies the confusion. Please let me know if there are still any questions!

Language Feature VS Smart Contract

@katelynsills

[...] it seems like one of the major reasons for this FLIP is so that every account doesn't need to deploy a contract to delegate access to their AuthAccount.
What's the main issue with this? Is it storage space (thousands of identical contracts being deployed)?
If so, it seems like there might be alternatives that haven't yet been discussed.

There are a couple of reasons why this feature is being proposed as a language feature rather than implementing it as a contract.
One is the number of contracts, not just the size: Every account would need a contract. With millions of accounts, this is currently not technically feasible.
Another reason is that the group believes that the child-account pattern will be so widely used, that it will be a core approach to building dapps, and thus should be easily available in the language (initializing account with a contract adds friction).

There are indeed alternatives that were discussed for the use-case.
I will include the reasoning above and the alternatives for the use-case into the FLIP.

Next Steps

@bluesign

We can make longer and more extensive FLIPs

Agreed. As mentioned above, I will extend the FLIP with the requested details.
I will also try to rememeber this in future FLIPs.

@bluesign

Brainstorming sessions can involve community and we don't see the PR first.
[...] Maybe we start a working group for this ?

Agreed. We have public brainstorming sessions for other topics and proposals, it seems like a good idea for this proposal too.

@bluesign

Anyway safe to say this didn't get community approval, what is the next step ?

Proposal reviews are an iterative process.

This proposal got some initial feedback and it is clear that it will not get accepted in its current iteration: it requires more detail and potentially needs to be amended to propose additional functionality or a variation of the currently proposed feature.

As with any other proposal, the next step is for the authors to go back and work on the next iteration of the proposal, and we are looking forward to get more feedback from everyone on that next iteration! 🙂

@bluesign
Copy link
Collaborator

bluesign commented Dec 15, 2022

First of all thank you @turbolent

I am on phone so will write a bit brief. Quoted usecase from @dete (if understood correctly) very important need, but I don’t understand why use just big hammer for this.

Child accounts allow users to sign up for new experiences using standard Web2 account management, and then, when they are ready for all of the features of Web3, they can attach a wallet as a parent account and have full access to all of their assets in all of their applications.
As a bonus, this mechanism allows for applications to manage the assets in their "domain" without having to incessantly ask for signing permission, while keeping all of the assets outside their "domain" secure, but accessible by asking for permission.

  • Why not define the child account?

Such as:

ChildAccount(payer: AuthAccount) : Capability<&AuthAccount>

This way we can separate child account and main accounts at creation type, no dangerous get auth account capability needed, also reuse the part from implementation.

Cause I am really maybe too much pressing on this but this getting auth account capability is not “sugar”. This is like saying: “oh you can do that by installing kernel extension (driver) already, we just made it easier by allowing at userspace”

@turbolent
Copy link
Member Author

@bluesign The idea is that the child account potentially created first, and then later associated with a parent account.

@bluesign
Copy link
Collaborator

bluesign commented Dec 15, 2022

@turbolent yeah this allows this. Payer is dapp, getting capability to AuthAccount. Then can give this to Master account. (When linked)

This way normal accounts will not have access to this, and we can know which account is child account (which dapp created) linked to which master account.

Also this removes all security risks. Even we can have a Bool field on authaccount showing this is ChildAccount

if the use case is just ChildAccount and linking , this should cover without causing any trouble.

@bluesign
Copy link
Collaborator

Btw in the same topic, I think we should also close control deploy loophole for AuthAccount access. But I think it should be another FLIP. It is pretty dangerous (as we don’t have remove contract)

@sisyphusSmiling
Copy link
Contributor

@bluesign your idea of a second class ChildAccount is interesting, and I can see how introducing a new type of AuthAccount would mitigate some of the security issues you and others have brought up. There has been discussion questioning even the idea of a top-down view on account associations that the "parent-child" verbiage implies. One could conceivably have a network of accounts. E.g. I maintain the following accounts, each having stated Capabilities:

  • 0x123 has Capabilities on 0x234 and 0x345
  • 0x234 has Capabilities on 0x345 and 0x456
  • 0x345 has a Capability on 0x234

In this case 0x123 is the "parent" or "root" account, but its child-accounts also have child-accounts.

Why would this be helpful? Well imagine game DApp clients maintain child accounts, issuing Capabilities to the user's main account (the parent account). As a user, I might have DApp clients on my mobile phone, and my laptop, and my gaming PC. Am I going to want to manage transfer of those assets across all of my DApp-related child accounts just to make sure those assets are where I need them to be when I want to play on my device of choice? If I wouldn't want to deal with that mess, a user surely wouldn't.

You could imagine how allowing child accounts to maintain capabilities on other child accounts would be helpful in that example. I could permission the child accounts on my mobile, laptop, and PC DApps on each other, and manage all of my assets (via some in-game UI and my wallet) across them regardless of the device or local child account I'm interfacing with. Interacting with an associated account is just an entry point into my graph of accounts. In that way, the child accounts being discussed here are "child" accounts in so far as they are intended to have a superseding "parent" account. But my thoughts are that they should also be able to maintain Capabilities on other accounts if we collectively decide Account Capabilities are a good path forward.

@sisyphusSmiling
Copy link
Contributor

Two things that I'd like to add that would be helpful for this feature:

  1. A notion of child accounts native to an AuthAccount - say a struct containing AuthAccount Capabilities. Though, I'm not sure if it's possible to enforce that as the only mechanism to collect AuthAccount Capabilities which, if not, would make it a weak source of truth.
  2. A notion in the child account of accounts with Capabilities on it. Perhaps this will be covered by CapCons, but it should be as evident to a user that a Capability was issued on their AuthAccount as keys being added.

I imagine these features would increase auditability & assist wallet providers in representing both a user's child accounts and any permissioned parent accounts.

@bluesign
Copy link
Collaborator

bluesign commented Dec 16, 2022

@sisyphusSmiling I think your child account can have many parents in my proposal. Also child account and its master can share authaccount with another child
Account. (Child account on creation gives a capability, dapp can save and clone this capability and give to child and master accounts)

you need to think child accounts as puppets. Dapp and user can both control the puppet. And they both can extend who can control the puppet.

but puppet can never control the master.

so puppets having access to puppets is ok.
Puppet having access to master is not. (And also not needed)

PS: I really like this idea, when we separate child
and master, this will be really useful. And also great for onboarding. My only concern is security. If this doesnt cover the use case, we can think more on it.

@sisyphusSmiling
Copy link
Contributor

sisyphusSmiling commented Dec 16, 2022

@bluesign Agreed! I'm interested in the language-level implications of this distinction between accounts as that's not in my wheelhouse. @turbolent what are your thoughts?

I also think that because of the power of this feature, access to this Capability should be as direct as possible. This is especially important because it is possible to copy Capabilities, and we wouldn't want anyone other than those authorized to maintain access to the ChildAccount.

I'm thinking the process of issuing & claiming the Capability might look as follows:

Child Account Model

  1. ChildAccount calls account.parentAccounts.delegateToParent(parentAddress: Address)
  2. A capability to the child's AuthAccount is linked, retrieved and inserted into a mapping indexed on the parent's Address. One consideration here is how we might prevent access to that Capability through the standard getCapability() API.
  3. To claim the Capability, the parent AuthAccount calls account.childAccounts.claimAsDelegate(childAddress: Address)
  4. A call (retrieveChildCap(): Capability<&ChildAccount>?) is then made to the specified childAddress's account.parentAccounts to retrieve the Capability.
  5. Assuming the calling parent account is the one listed as a parent on the ChildAccount, the Capability indexed on the parent's Address is returned. Note: if we want to maintain knowledge of parent accounts, we could either replace the value with nil or perhaps define two mappings (pendingParentAccounts and claimedParentAccounts) which would define delegates who have been permissioned versus those who have claimed their permissioned Capabilities.
  6. Finally in the parent's AuthAccount, the returned Capability is inserted into a mapping of ChildAccount Capabilities indexed on child account addresses

When a parent wants to use a ChildAccount Capability, they can call to account.childAccounts.get(childAddress: Address): &ChildAccount which returns an ephemeral reference to the ChildAccount for use in the transaction. The ephemeral nature of the reference means that the returned value cannot be stored.

This largely functions similarly to the publish() & claim() mechanisms of AuthAccount.Inbox, but is more direct and prevents access to the Capability directly which I believe is an important security consideration. I realize this construction increases the scope of implementation compared to what's proposed in this FLIP, but I'm curious if others feel this addresses many of the security concerns voiced in this discussion.

Some open questions remain in my mind:

  • Should you be able to grant a Capability on a ChildAccount from another ChildAccount, or should we require the Capability be issued directly from the ChildAccount?
  • How can we prevent access to the Capability via existing getCapability() API?

@cybercent
Copy link

cybercent commented Feb 16, 2023

This essentially allows one account to have complete control over another.

It looks powerful and it could help with account setup and recovery, but there is an obviously risky use case when the controlling account is compromised all the controlled accounts could be compromised as well.

Comparable to adding one's private key to another user's account.

@bluesign
Copy link
Collaborator

@cybercent there is a very nice implementation example linked from the forum. Basically I think if we can make a standard contract wrapping the capability, we can somehow prevent misuse a bit. But yeah it is a big hammer.

@jacob-tucker
Copy link

jacob-tucker commented Feb 20, 2023

Hello, just chiming in to ask why it is possible to link the AuthAccount to the public domain.

I can understand a reason for private paths. Walletless onboarding etc. I also looked at this example in-depth and can understand the use case for private capabilities, although I still do not like that we are breaking an anti-pattern we have forbidden for a few years now by passing the AuthAccount into the contract.

However public does not seem like it would ever be used and is extremely dangerous. All it would take is sneaking signer.linkAccount(/public/Test) into a transaction to open up someone's account.

I propose preventing linkAccount from being used in public and only allowed in private. I think it would be much safer this way

@bluesign
Copy link
Collaborator

I think we cannot limit it like this, or someone malicious just can put into a resource anyway @jacob-tucker

I checked the example too, for me still all feels wrong but looking at the bright side; maybe this can change walled gardens a bit. (dw etc)

@jacob-tucker
Copy link

Agreed it feels wrong to me too @bluesign

Although even if possible through putting a private capability into a resource, I still do not think public domain should be allowed. Any way we can make it harder for this to be exploited is good in my mind

@joshuahannan
Copy link
Member

I agree on wanting to not allow it in the public account domain. Any reason we can't make that restriction?

@sisyphusSmiling
Copy link
Contributor

+1 on public linking. It's not necessary for account linking with respect to walletless onboarding and it's hard to think of a use case. I know it goes against Capability-based security patterns, but if there's enough concern about it among the community, especially about the feature in practice, then perhaps it should be avoided. We'll be doing away with public/private path distinctions anyway with CapCons, right @turbolent?

@j1010001
Copy link
Member

j1010001 commented Mar 2, 2023

@jacob-tucker not sure you have seen this, so just wanted to make sure you have: onflow/cadence#2353

@sisyphusSmiling
Copy link
Contributor

sisyphusSmiling commented Mar 2, 2023

Two things have occurred to me recently:

Visibility on account linking

I believe it would be helpful to monitor account linking events. We can build events into the proposed standard ChildAccount contract (#72), but since account Capabilities can be linked outside of that standard, it would be helpful to index any instance where a Capability is linked. That might look like:

pub event AuthAccountLinked(address: Address, path: PrivatePath)

In addition to the proposed transaction pragma, this event would give wallet providers a data point to determine when a user's account (and potentially any of their child accounts) has been linked, adding visibility & potential notifications around a sensitive security vector (similar to adding keys on an account). It could also help auditability, enabling us to determine whether an AuthAccount Capability has previously been linked. Would it be possible to emit such an event whenever an AuthAccount Capability is linked @turbolent?

Auditability of issued AuthAccount Capabilities

With a focus on security, I'm concerned that we lack a mechanism to know whether multiple Capabilities have been issued if they are linked at the same path. Emitting the event discussed above at least gives wallet providers a mechanism to determine whether an account was previously linked and the relevant Capability path.

However, seeing one linking event doesn't mean that only one Capability has been issued. I could link an AuthAccount Capability, then retrieve it n times - the wallet would have no idea how many have been issued from that path. I think, at least until CapCons enter the picture, it would be helpful to emit an event any time an AuthAccount Capability has been linked and additionally whenever it has been retrieved if possible. IOW, linkAccount(PrivatePath) and getCapability<&AuthAccount>(PrivatePath) would emit events. Something like the following in addition to the event mentioned above:

pub even AuthAccountCapabilityRetrieved(address: Address, path: PrivatePath)

Would emitting this event be feasible and/or practical? I know CapCons + SuperAuthAccount are the long-term solution which will resolve the concerns around auditability & revocation, and we can't totally address the inherent custodial risk of shared account access, but any tools we can give wallet providers to enhance visibility would be welcome.

@turbolent
Copy link
Member Author

Thank you everyone for the great feedback. I just updated the FLIP and made the following changes:

  • Account links must be private. The path parameter type changed from CapabilityPath to PrivatePath
  • The linkAccount function emits an event of type flow.AccountLinked
  • Account linking is only available if the #allowAccountLinking pragma is declared

@jacob-tucker
Copy link

Awesome to see those updates @turbolent - personally I'm very comfortable with this now and excited to share to the community

@turbolent
Copy link
Member Author

This feature, with the additional safety changes described above, is going to be deployed to Testnet today, March 8th.

We would love to get as many eyes on this release, so we’d like to ask all of you to test the new feature and provide further feedback on the implementation.

We would also like to encourage everyone to look for any potential security vulnerabilities related to this feature - we reward issues that are reported through our Responsible Disclosure with a generous bounty (https://flow.com/flow-responsible-disclosure).

If we don’t find any new issues or receive negative feedback during this final testing, we plan to accept the FLIP and release this feature on Mainnet on March 22nd.

Thanks everyone!

@jacob-tucker
Copy link

jacob-tucker commented Mar 16, 2023

Hi @turbolent , I recently saw this transaction on testnet: https://testnet.flowscan.org/transaction/cc7959d414839b5851429bea145bb5e11c42c271eca6e8e370d96883323404ed/script

Although it doesn't have the pragma in the transaction, the transaction still went through. I noticed the pragma is instead at the top of this contract, which may be why it's allowed: https://testnet.flowscan.org/contract/A.1b655847a90e644a.ChildAccount/overview

I suggest we enforce the pragma in the transaction even if the linking is happening in the contract, otherwise I don't see much point in the pragma. Developers can always put it in contract code and users will never see it in their transaction code when wallets ask for approval.

Edit: I still think @bluesign 's suggestion is also very nice, that it should be enforced at the top of the transaction as well:

One minor suggestion, can we force this to be declared on the top of the transaction? This way even wallets does not support (warning etc), user can see easily.

@SupunS
Copy link
Member

SupunS commented Mar 16, 2023

@jacob-tucker Thank you for the feedback as always 🙏

I suggest we enforce the pragma in the transaction even if the linking is happening in the contract, otherwise I don't see much point in the pragma.

This exact behavior was added in onflow/cadence#2383, and was deployed on testnet yesterday (15th). The transaction you pointed out was executed before the testnet update (i.e: on 14th) and hence has the old behavior.

With the new behavior, transaction will fail if they haven't declared the pragma in the transaction itself, even if the contract declares it.
e.g: https://testnet.flowscan.org/transaction/17440461c057d5169e2cd1109ab629f37fcf9984c7e6cbb689b37b0374f52637/script
(thanks @sisyphusSmiling for the example!)

@wfalcon0x
Copy link

wfalcon0x commented Mar 16, 2023

The same transaction was still working about an hour ago though: https://testnet.flowscan.org/transaction/981fd6a429fdc931fa24b565da5ccf026cbd28a91cd2c61679f70aa40edfe017/script

I think what Jacob was trying to suggest, that even if the pragma is already in the smart contract that is being called by the transaction, it should be also required on the transaction level.

@SupunS
Copy link
Member

SupunS commented Mar 20, 2023

The same transaction was still working about an hour ago though: https://testnet.flowscan.org/transaction/981fd6a429fdc931fa24b565da5ccf026cbd28a91cd2c61679f70aa40edfe017/script

I had a detailed look at the transaction again, and as I understood, it doesn't use accounting linking during the execution.
The transaction creates an account using the ChildAccountCreator.createChildAccount() method, which doesn't use account linking.
Auth account linking is only used inside the ChildAccountManager.createChildAccount() method, which is not used in that particular transaction. So it is correct that the transaction passes as it does not use account linking, and the behavior this still the same as what was described above.

I think what Jacob was trying to suggest, that even if the pragma is already in the smart contract that is being called by the transaction, it should be also required on the transaction level.

Yes, this is the current behavior.

@turbolent
Copy link
Member Author

Given that there has been no further negative feedback, the FLIP has been accepted.

The FLIP is already implemented and deployed to Testnet. It will get deployed to Mainnet tomorrow (2023-03-22), at which point I will change the status to implemented.

I would like to thank everyone for their great feedback, and invite everyone to continue the conversation in two places:

  • The account linking function is a temporary API which fits into the existing link-based capability API.
    The Capability API is proposed to be replaced in FLIP 798.
    I recently added account capability functionality to the proposal (in preparation of the acceptance of this proposal) and would love feedback.
  • Adding guard rails in the form of entitlements for the account type is being incubated in https://forum.onflow.org/t/super-user-account/4088

@turbolent turbolent merged commit 84628a8 into main Mar 22, 2023
@turbolent turbolent deleted the bastian/authaccount-capabilities branch March 22, 2023 00:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Drafted
Development

Successfully merging this pull request may close these issues.

None yet