EOSIO / eos

An open source smart contract platform
https://developers.eos.io/manuals/eos
MIT License
11.27k stars 3.6k forks source link

Support reading current transaction permission #6210

Closed andresberrios closed 4 years ago

andresberrios commented 5 years ago

To have more granular control over the permissions granted to a contract, it would be useful for developers to adopt a pattern in which they can read the current transaction's permission and forward it when sending inline actions to other contracts.

Currently, for a user to authorize a contract to send an inline action in their name, they can only add the eosio.code permission for the contract in their account's active authority, since contract actions generally do not take a parameter to specify the authority that should be used for the inline action, so they default to active.

It would be more secure to allow users to set up a new dedicated permission for that contract's action, and then linkauth that permission to both the desired contract action and the inline action that the contract is sending. It would also be necessary to use eosio.code (or a related proposal as discussed in https://github.com/EOSIO/eos/issues/3050), but the permission would have much more limited access than the active permission.

Then, as explained, the contract would need to do one of the following:

  1. (Not practical) Take an action parameter that specifies what is the authority that should be used for the inline action.
  2. (Better UX) Read the current transaction's authority and reuse it for the inline action.

Please give your thoughts when you can @arhag

arhag commented 5 years ago

Personally, I think the more explicit nature of option 1 makes more sense than option 2.

Another option (option 3) that I think would be better than both is allow the user to setup the contract tables (via other contract actions) with the mappings needed by the contract to determine the appropriate permission that the contract should use for inline actions authorized on behalf of their account.

Also both options 1 and 3 can work with the existing intrinsics of EOSIO.

By the way, option 2 relates strongly to #5379. The feature requested in this issue enables a more general version of the existing require_auth2 and the proposed has_auth2 from #5379 in that the contract could read the authorizations vector and do all the appropriate checks on the WASM side (which could actually be faster if more than one authorization needs to be checked).

But we have been discouraging the usage of require_auth2 which begs the question whether it is moving in the right direction to introduce a has_auth2 intrinsic or the ability to read action authorizations as requested in this issue. The reason for the discouragement is due to the fact that require_auth2 (and their proposed variants) allow the contract to enforce permission levels which takes control away from the user.

Ideally the contract would never be concerned about the permission levels, and the native actions updateauth, deleteauth, linkauth, and unlinkauth would be used by the user to entirely manage the security level they wish to require for the various actions.

On the other hand, I do see the utility in require_auth2 sometimes. I even used it in my proposed implementation of eosio::unfreeze in #6150. And since require_auth2 already exists, permission levels in the authorization of an action already have side-effects on contract execution (not just transaction validation). So maybe it is appropriate to just go all the way and allow contracts to access the full authorization vector.

andresberrios commented 5 years ago

Thanks for your comments @arhag.

I agree with your point about option 2 being too implicit, that's not a desirable thing. I simply was trying to come up a way that would reduce the amount of implementation burden on the developers to allow for this permission forwarding. Option 1 requires less code, but option 3 would need quite a bit of boilerplate code on the developer's side for each contract, and each of these implementations would be essentially the same, to the point that it would be desirable to have it standardized and provided maybe at the contract API level to directly use if needed, or at the intrinsics level somehow to just get it for free without any increase in contract sizes or implementation burden. If nothing else, I think it would make sense to evangelize the usage of the pattern of option 1 (and making the parameter optional defaulting to active?), similar to how generally the acting account name is sent in the actions parameters instead of it being read from the transaction authorizations.

Ideally the contract would never be concerned about the permission levels, and the native actions updateauth, deleteauth, linkauth, and unlinkauth would be used by the user to entirely manage the security level they wish to require for the various actions.

I very much agree with this, as it would be better for everyone if for almost all the cases, the contracts would only require auth without specifying the permission level and that way the user can simply link custom permissions to them. As you mentioned, there are a handful of cases where it does make sense to require a specific permission, but this would be limited to only the default permissions (active and owner), since other than those, the contract should have to say in what the name of the permission level should be, that's up to the user. Hence, it might make sense to limit require_auth2 and has_auth2 to only active and owner, maybe calling them something different like require_owner, has_owner_auth, require_active, is_active_auth.

aclark-b1 commented 4 years ago

In order to focus our efforts on issues that are currently creating difficulty for the community we are closing tickets that were created prior to the EOSIO 2.0 release. If you believe this issue is still relevant please feel free to reopen it or create a new one. Thank you for your continued support of EOSIO!