Liking cljdoc? Tell your friends :D

Upgrading an existing app to permissions

An app built before groups, roles and permissions runs with :wagoe/authorization absent, which is :off: any signed-in user passes every route, and the admin admits users with role :admin. bb upgrade authorization moves such an app to :enforce in four steps, and at each one says who would lose or gain access. Nothing changes for an app until you run the steps. The model itself is in Authorization.

Before you start

  • Bump every com.wagoe/* in deps.edn to this release. The steps run in your app, against its database and its routes.

  • An app generated before this release has no bb upgrade task. Copy it from a new app’s bb.edn, or run wagoe upgrade authorization <step> with the CLI instead; they are the same command.

  • The steps work on one environment: --env prod, or $WAG_ENV, dev when neither is set. They read resources/conf/<env>/config.edn and the database it names. Try them on a copy of the production database first.

Each step can be run again. prepare and enforce take --dry-run, which prints what they would write and writes nothing.

1. Check

bb upgrade authorization check --env prod

Writes no config and moves no rights; like any start, it creates user tables that are missing. It prints:

  • whether deps.edn is behind the CLI;

  • the mode in config.edn, a :require-role in :wagoe/admin, and each OIDC provider’s :default-role;

  • admin entities missing from :wagoe/admin :entity-discovery :allowlist: the admin declares admin.<entity> permissions only for the allowlist, so under :enforce only a platform admin reaches the others;

  • pending migrations;

  • how many users hold each stored role: platform admin, admin in a tenant, user, viewer;

  • what the first start of this release does to rights (below);

  • the routes no rule covers, which :enforce refuses to all but a platform admin.

:default-role is not rewritten: decide which group those users belong in, by the user module’s :group-membership hook or by hand, then delete it.

2. Prepare

bb upgrade authorization prepare --env prod --dry-run   # look first
bb upgrade authorization prepare --env prod

It deletes :require-role, which nothing reads any more, adds the admin’s entities to its :allowlist, sets :wagoe/authorization {:mode :report} if the mode was :off, runs the migrations, and starts the app once without serving. That first start moves the old rights, as every start of this release would:

  • Everyone, the built-in group of all users, gets every module’s editor role, but not one holding a permission something already checks: one a module declares itself, or one a group grant names.

  • Users with role :viewer join a group called Readers, which gets every module’s viewer role, and their role is cleared.

  • Each group grant becomes a managed role named after its permission, held by the same group in the same scope.

  • Nobody becomes an admin.

It then prints every group with its roles, what each user holds, grouped by users who hold the same, and where :enforce would decide differently from :off.

3. Report

Run the app under :report through a normal week. Nothing is refused; each request :enforce would refuse is logged once a minute per user, route and permission:

WARN ... Authorization would refuse this request under :enforce {:mode :report, :user-id #uuid "…", :route /api/v1/orders, :method :post, :permission :orders/write, :reason :forbidden}
bb upgrade authorization report --env prod --log logs/app.log

It prints the routes without a rule and the differences from :off, worked out from each user’s current rights, and with --log the logged refusals per permission and route, with the users refused. A generated app logs to the console, so point --log at wherever your process manager keeps it. It exits 2 while anything would be refused.

Close each difference: give the route a rule (:public, :authorization :signed-in, :permission), or give a group the role at /web/admin/groups. Run report again until it says none.

4. Enforce

bb upgrade authorization enforce --env prod --log logs/app.log

It sets :mode :enforce, and refuses to while the mode is still :off, a route has no rule, a user would be refused or held to a scope, or the log holds a refusal. --force switches anyway, for differences you mean, such as viewers who should not write. Restart the app afterwards.

To roll back, set :wagoe/authorization {:mode :report} in the same file and restart. Rights stay as they are, so you can switch again later.

Once enforcing, narrow Everyone: replace the editor roles the upgrade gave it with what every user should have.

What is compared

Under :off, every signed-in user passed every route, and the admin admitted role :admin. For each user the steps compare that with what :enforce decides from the user’s rights:

  • refused: the user lacks the permission, or the route has no rule;

  • held only in a scope: the user holds the permission only for part of the data, so :enforce narrows what they see;

  • newly held: an admin permission someone who was no admin now holds.

A platform admin, role :admin with no tenant, passes everything and is never listed. A route whose handler checked a role itself under :off shows up as refused for users who never reached it; that is no loss.

Verifying

After each step, check by hand as well:

  • A user’s Rights tab, /web/users/<id>/rights, lists each permission with the group and role it comes from.

  • /web/admin/permissions/view?name=orders/write shows who holds a permission.

  • Sign in as a test user of each kind, an old user, an old viewer and an admin in a tenant, and use the pages they use.

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close