<div dir="ltr"><div><div>As of 02c2b10067bbe2169c2b7a7cfb88c66f9bc69700 in master, there are new permission options available.</div><div><br></div><div>The current permissions, formerly known as **acls** and used to "**share models**" allow controller administrators to give both internal and external users different permissions in models and controllers.</div><div><br></div><div>=============</div><div>What changed?</div><div>=============</div><div><br></div><div>In the CLI.</div><div>===========</div><div><br></div><div>Formerly you could create a user and "share" a model with a level of permission:</div><div>  - read</div><div>  - write (to all effects was equivalent to admin)</div><div>  - admin </div><div><br></div><div>all could be done with one command:</div><div><br></div><div>``juju add-user <username> [--acls="level"] [models...]``</div><div><br></div><div><br></div><div>or in two commands:</div><div><br></div><div>``juju add-user <username>``</div><div><br></div><div>``juju grant --models=one,two,... --acl="level"``</div><div><br></div><div>Currently the user creation command allows only for the creation of the user, and permissions, now being more extensive than a simple attribute of the model, are granted separately.</div><div><br></div><div>For granting permissions</div><div>************************</div><div>A simplified grant command is now available:</div><div><br></div><div>Permissions can be granted to a user in multiple models with the following syntax:</div><div><br></div><div>``juju grant <username> <permission> [model1 model2 ... modelN]``</div><div><br></div><div>**If no model is provided, the command will try to set the permission at a controller level.**</div><div><br></div><div>* For Models , the available permissions are:</div><div> - read (loosely, gives the ability to query the model data, ie juju status)</div><div> - write (gives the ability to modify the world at a model level)</div><div> - admin (gives the ability to perform meta actions)</div><div>permissions are cumulative so, each one gives the previous.</div><div><br></div><div>* For Controllers, the available permissions are:</div><div> - login (default for all users unless explicitly revoked)</div><div> - addmodel (the user can add models to the controller)</div><div> - superuser (the user is controller administrator, default for the controller owner) </div><div>as with model permissions, they are cumulative.</div><div><br></div><div>For revoking</div><div>************</div><div>the command is similar:</div><div><br></div><div>``juju revoke <username> <permission> [model1 model2 ... modelN]``</div><div><br></div><div>Revoking a level will leave the user with the previous one or none if the level is **read** or **login**.</div><div><br></div><div>In the API Server</div><div>=================</div><div><br></div><div>Previously, permission checking was done by a set of rules on the method finder (in *apiserver/client_auth_root.go*)</div><div><br></div><div>This was not in accord with the original intent of the architecture, which included an *authorizer* in the facade instances to do the permission checking.</div><div><br></div><div>Authorizer gained a **HasPermission** method which has the following signature:</div><div><br></div><div>``HasPermission(level, object) (bool, error)``</div><div><br></div><div>Which returns whether the logged in user has that level of permission on the passed object, currently the passed object can either be a *names.ControllerTag* or a *names.ModelTag* and the level one of the aforementioned, which are defined as  *description.Access* constants in *core/description/access.go*.</div><div><br></div><div>There is an additional **UserHasPermission** that has an extra user argument, that takes a *names.UserTag* in case you need to add the level for a user other than the one logged in.</div><div><br></div><div>``UserHasPermission(user, level, object) (bool, error)``</div><div><br></div><div>In most facades there are now convenience methods (mostly called checkCanXXXX that err if the logged in user cannot perform said action) that are now called in the facade methods before anything is done to ensure the user can perform such action or return *common.ErrPerm*.</div><div><br></div><div>In the tests.</div><div>=============</div><div><br></div><div>Implementations of **fakeAuthorizer** became a bit smarter and can now return true/false when their **HasPermission** is called depending on the name of the user and/or the AdminTag parameter.</div><div><br></div><div>Tests have been fixed accordingly to assume the user running them has the right permissions since that was the intent of the tests author but you are encouraged to review your facade method tests and add various permission cases where such paths are not explored.</div><div><br></div><div>In the future.</div><div>==============</div><div><br></div><div>Facade Methods</div><div>**************</div><div>To ensure security and consistency, new facade methods should always begin with a call to **HasPermission** (if any level of permission is required) otherwise the default permission for a logged in user will be the minimum expected, please try to be explicit with the level requirement to be future proof.</div><div><br></div><div>If you can add what kind of user the facade method is intended for in the method doc it can help a lot in debugging if there is any permission issue.</div><div><br></div><div>Tests</div><div>*****</div><div><br></div><div>Future tests should now explore different permission path, a minimum acceptable should be checking for at least the expected accepted and one expected not accepted permission level.</div><div><br></div><div>Missing Tests</div><div>*************</div><div><br></div><div>Since now all facade methods have an extra dimension, some new paths might be untested, you are encouraged to add said paths should you stumble upon it while doing nearby work.</div><div><br></div><div>The review checklist.</div><div>*********************</div><div><br></div><div>New items should be added to the checklist for cases where the reviewed code is a facade.</div><div><br></div><div>* Make sure there is a permission checking at the top.</div><div>* Make sure the doc mentions the target user.</div><div>* Make sure the tests for the facade explore all required permission paths.</div></div></div>