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

Policy enforcing on users #2552

Merged
merged 13 commits into from
May 3, 2024
Merged

Conversation

CDimonaco
Copy link
Member

Description

This pr creates the bodyguard policy for user management endpoints.
We create default abilities and attach them to default admin in the release task.
The /api/v1/users endpoints are protected. Only accessible to all:all or users:all

How was this tested?

Automated tests

@CDimonaco CDimonaco added enhancement New feature or request elixir Pull requests that update Elixir code labels Apr 25, 2024
@CDimonaco CDimonaco self-assigned this Apr 25, 2024
Copy link
Contributor

@arbulu89 arbulu89 left a comment

Choose a reason for hiding this comment

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

Hey @CDimonaco
The code looks great in general.
My unique real concern is that we don't test the policy completely.
For example, the users:all ability is not tested.
I think we should have pure tests for the policy itself (together with the controller if you want).
They are so easy to test that it doesn't look a big deal.

lib/trento/users/policy.ex Show resolved Hide resolved
lib/trento/users/policy.ex Outdated Show resolved Hide resolved
test/trento_web/controllers/v1/users_controller_test.exs Outdated Show resolved Hide resolved
Copy link
Contributor

@arbulu89 arbulu89 left a comment

Choose a reason for hiding this comment

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

Nice @CDimonaco
Thanks

end)
end

test "should disallow other abilities" do
Copy link
Contributor

Choose a reason for hiding this comment

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

What is this test for? I would expect some refute as the test talks about disallow, but checking it, i think we can just simply remove it

Copy link
Member Author

Choose a reason for hiding this comment

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

I refactored the test, for some reason I had the working copy not committed lol

@@ -47,7 +49,7 @@ defmodule Trento.Users do
|> Repo.insert()
end

def update_user(%User{id: 1}, _), do: {:error, :operation_not_permitted}
def update_user(%User{id: 1}, _), do: {:error, :forbidden}
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if you've considered having a module attribute as a named constant for the numeric value 1?

Comment on lines +90 to +92
# Attach all:all ability
%Trento.Abilities.UsersAbilities{}
|> Trento.Abilities.UsersAbilities.changeset(%{user_id: admin_user_id, ability_id: 1})
Copy link
Contributor

Choose a reason for hiding this comment

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

A named constant here for the value 1, e.g. ability_id_for_all could be interesting to consider, since the numeric id has a special meaning.

Comment on lines +4 to +8
def up do
execute "INSERT INTO abilities(id, name, resource, label, inserted_at, updated_at) VALUES (1, 'all', 'all', 'Permits all operations on all the resources', NOW(), NOW())"

execute "INSERT INTO abilities(id, name, resource, label, inserted_at, updated_at) VALUES (2, 'all', 'users', 'Permits all operations on user resource', NOW(), NOW())"
end
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder what were the considerations to make it necessary to load abilities from the db? For instance, I'm curious why can't there be static abilities, i.e. at the code level? (Maybe I'm thinking too much along a role-based approach, and there is a different/more granular approach that has been agreed here for this.)

Copy link
Contributor

Choose a reason for hiding this comment

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

Because using migrations is really convenient to execute/rollback the actions.
Otherwise, we would need to add seeds/release actions to add them. And the same would happen if you want to remove. You would need to explicitily remove them in the code, which would become error prone

Copy link
Contributor

Choose a reason for hiding this comment

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

I see, thanks for the explanation. My comment was a bit broader, though, on the overall approach of loading/storing abilities in the db in the first place, but I guess maybe that is necessitated due to the access control meta-approach considered (RBAC vs granular ability based, etc.).
On a somewhat side note: I have been reading a bit into Cedar recently, and they have some interesting ideas about checking/validating static policies that are decoupled from the application code completely, using some formal methods/tools that give better assurances. It might be interesting to evaluate too, at some point.

@CDimonaco CDimonaco merged commit c73e6a9 into user_management May 3, 2024
26 checks passed
@CDimonaco CDimonaco deleted the policy_enforcing_on_users branch May 3, 2024 08:15
arbulu89 pushed a commit that referenced this pull request May 8, 2024
* users context return user abilities

* LoadUserPlug load the user from the database using stateless user

* Wip on user controller policy

* Refactor abilities

* User controller renamed to users controller

* Refactored user openapi schemas

* Users controller policy usage refactored

* Add basic permissions

* Users controller abilities refactored

* mix credo

* addressing review feedbacks

* mix credo

* Fix policy test
arbulu89 pushed a commit that referenced this pull request Jun 25, 2024
* users context return user abilities

* LoadUserPlug load the user from the database using stateless user

* Wip on user controller policy

* Refactor abilities

* User controller renamed to users controller

* Refactored user openapi schemas

* Users controller policy usage refactored

* Add basic permissions

* Users controller abilities refactored

* mix credo

* addressing review feedbacks

* mix credo

* Fix policy test
arbulu89 added a commit that referenced this pull request Jun 25, 2024
* Basic User management (#2529)

* Enforce password security un user schema

* Argon2 hash algorithm for user password

* Add fullname and email fields to user schema

* Mix phx gen json scaffolding for users

* Users context

* mix format

* User controller refactored for the new users context

* Pow custom context for getting non-deleted users

* Unique email for users

* Update release task and seed for users

* Users context prevents deletion of user with id 1

* Username cannot be updated

* Created and updated timestamps in users view

* Change of the username when users are deleted

* Add lock feature to Users

* Locked and deleted users are excluded from renew

* Session controller tests updated

* /me endpoint returns also user id

* User socket authenticatio

* User controller broadcast user actions on user topic

* Access token expiration to 3 minutes

* Fix could not delete admin user in context

* Trento default admin enabled

* User controller with spex

* Fix app jwt auth plug test typo

* User controller actions are dispatched to per user channels

* fix access token test

* fix alias in factory file

* mix credo

* fix mispell

* mix credo

* removed comments from user_controller_test

* Addressing review feedbacks

* Introduced users factory

* Addresing feedbacks

* Updated trento_dev sql regression dump

* Revert "Updated trento_dev sql regression dump"

This reverts commit ccce860.

* Ecto seed with user password update on conflict

* Run db seed on regression tests

* Listening to user related events on the frontend (#2542)

* Frontend socket authentication refactored

* Add logged user in the state when user performs login

* Subscription to user topic on user login

* Guard component put user in state after me call

We need to enrich the user in the store not only on login
but also when the session is valid, we already call the me
endpoint in the guard to get user details, we store these details in the
state to have always consistency between the logged users on the backend
and the user in the store (returned from me endpoint at each app load)

* Listening on user actions event in the frontend

* Addressing review feedbacks

* Create Abilities and UserAbilities schema (#2543)

* mix.gen.context Abilities

* Users abilities

* Addressing review feedbacks

* Mix format

* Install make and gcc in container and rpm (#2553)

* Install make in container and rpm

* Install gcc

* Add New User Management View (#2544)

* Add users view

* Add users view test

* Add users story

* Refactor and rename code

* Refactor file structure and imports

* Refactor users component

* Refactor user component and delete unused views

* Enrich user's story

* Remove empty components

* Add banner and update test

* Refactor users page and users

* Disable Create button while loading users

* Address comments

* Fix storybook

* Refactor test and test for deletion api call

* Improve factory and texts

* order and clean up code

* Split up tests and clean up

* Address final pr comments

* Create user form (#2548)

* Move api validation errors code to lib

* Add users api

* Add users factory

* Pass props to password component

* Add UserForm view

* Add CreateUser view

* Add CreateUser to the router

* Update password policy tooltip

* Use a more standard file naming

* Create dedicated function on save clicked

* Rewrite test descriptions

* Policy enforcing on users (#2552)

* users context return user abilities

* LoadUserPlug load the user from the database using stateless user

* Wip on user controller policy

* Refactor abilities

* User controller renamed to users controller

* Refactored user openapi schemas

* Users controller policy usage refactored

* Add basic permissions

* Users controller abilities refactored

* mix credo

* addressing review feedbacks

* mix credo

* Fix policy test

* Edit user form (#2566)

* Update UserForm to allow edition style

* Add EditUserPage

* Fix conflicts after rebase resolution

* Correct some typos and descriptions

* User profile routes (#2583)

* Update user profile in users context

* profile controller wip

* Prevent profile update for admin user

* Profile controller

* Add current password validation to the user schema when profile updates
password

* Current password field in profile update schema

* Addressing review feedbacks

* mix credo

* Add soft delete for email and update test (#2584)

* Enable user status update (#2591)

* Enable locking up user in creation

* Enable status select in frontend

* Disable edit button for admin user (#2592)

* Abilities controller and update (#2568)

* Add abilities controller and index endpoint

* Add and update abilities in user operations

* Adapt user controller to use abilities

* Load abilities in profile endpoint

* Delete user abilities on deletion

* Optimistic lock for users (#2595)

* Optimistic locking on user schema update

* wip on preconditions

* mix credo

* Add optimistic locking in users controller

* Add optimistic locking handling in EditUserPage

* fix typo in users test

* fix user schema

* Add top-right corner profile button & menu (#2590)

* Store email from /me endpoint in state

* Add and use new Profile Menu component

* Use profile endpoint instead of /me

* Fix users/profile controller tests (#2607)

* Fix users controller test adding if-match

* Add admin user in profile controller test to avoid 403

* Add a generate password button for the UserForm (#2576)

* Add generate password button for input form

* Disable password generation button if user is admin

* Multi select component (#2600)

* Add react-select dependency

* Create MultiSelect component

* Add className to component

* Update classNames usage

* Update value containers color

* Switch to use link in ProfileMenu (#2608)

* Users abilities frontend (#2611)

* Add abilities api

* Load abilities and user abilities

* Update tests and stories

* Forbidden guard for user entries (#2612)

* Update redux code to load user abilities

* Implement the ForbiddenGuard

* User ForbiddenGuard in users related items

* Add missing abilities field in the user state

* Add disabled prop to multi-select (#2620)

* Interpolate validation errors in error view (#2616)

* User Profile page (#2615)

* Moved common forms labels and components to @lib/forms

* Wip profile page

* User profile form stories

* Profile password change form

* ProfileForm test

* ProfilePasswordChangeForm test

* ProfilePage test

* Close password dialog when user click save in profile view

* fix tests

* User profile form disabled when the user is the default admin

* Profile form modal toggle lift up

* Addressing review feedbacks

* Multi select for permissions in user profile

* ProfilePage dispatch setUser command in redux when user is updated

* Updated usage of multiselect in profile form

* Address review feedbacks

* User edit create toast (#2613)

* Add success and error toast

* Add toast test for create user page

* Add error toast if user is not found

* Rescue StaleError in user update function when abilities are present (#2622)

* Password change request (#2624)

* Add password_change_requested_at field and logic

* Add new field to controller and api spec

* Add maybe_ prefix to conditional functions

* Change password change requested to boolean and add to admin view

* Change placeholders in UserForm and EditUserPage(#2626)

* Password change request frontend (#2625)

* Move the toast out of profile menu and change z-index

* Move toaster inside router so it can use router data

* Load password requested field in redux store

* Add ToastNotifications component

* Create new customNotify action

* Add password change request fork in sagan index

* Dismiss password change request notification

* Use password_change_requested as boolean

* Update notifications to allow receiving health icons

* Clean and improve e2e performance (#2630)

* Remove unused commands

* Load initial state only if needed

* e2e user management (#2631)

* Update login commands for multi user usage

* Remove actions from users factory

* Add users e2e tests

* Admin cannot be edited test scenarios added

* Remove empty describe

* Add validation when a password is generated (#2640)

* Refactor generatePassword function

* Refactor test, update tooltip and enrich backend

* Enrich password test list

* User totp fields (#2646)

* Add new totp field migrations  to the user

* Add new fields to user schema

* Validate totp_enabled_at can only be nil for admin update

* Fix credo error

* Topt enrollment backend procedure (#2651)

* reset totp for users

* topt enrollment context

* topt openapi payloads

* Renamed reset totp

* Changed error when totp is invalid in the totp enrollment procedure

* TOTP Procedure in profile controller

* fix mispelling

* Addressing review feedbacks

* Login with totp (#2647)

* Add update_user_totp function

* Add totp validation code

* Update session controller to authenticate with totp

* Fix session controller create schema code

* Filter out totp_code from phoenix logs

* Send totp_code in users saga login action

* Add totp input state in login page

* Remove required fields to avoid backward incompatible error

* Use common Input in login page

* Fix tests after conflict resolution

* Totp enrollment frontend (#2657)

* Totp enrollment box component

* totp enabled field in profile controller response

* Profile totp enrollment frontend procedure

* fix mispell

* Confirmation modal on totp disable

* Addressing review feedbacks

* Allow admin disable totp (#2658)

* Allow update of totp_enabled field to false

* Allow disabling totp feature from user mgmt

* Adjust formatting

* Remove unnecessary changes and improve UserForm changes

* Various cleanups & move code to controller

* Move the totp disabling to the context

* Improve test description

* Improve UserForm component

* Fix missed ===

* Remove default padding in the Select component

* Improve TOTP select disabled check

* Add update_user test for TOTP disable

* Address remaining feedback

* Policy support functions (#2670)

* TOTP authentication e2e tests (#2667)

* Move lock user tests to new describe

* Add TOTP tests

* Skip long lasting test by default

* Disabled guard (#2672)

* Move ForbiddenGuard to common

* Create the DisabledGuard component

* Update early return usage

* Improve cloneElement usage

* Make tooltip place a prop

* Refactor storybook functions

* Some small improvements in the user forms (#2673)

* Remove TOTP configuration in user creation form

* Add disabled state to Switch component

* Disable TOTP configuration for default admin

* Style TOTP enrollment box (#2674)

* Style totp enrollment box usage in profile form

* Use profileFactory in profile form tests

* Reword multi-factor text usage

* Update e2e tests

* Use proper command to login (#2712)

* Use proper command to login

* Add page reloads to get correct suma posted data

* Set python3 as ansible interpreter (#2713)

* Set python3 as ansible interpreter

* Pin ubuntu version for pr env ci stages

---------

Co-authored-by: Carmine Di Monaco <carmine.dimonaco@suse.com>
Co-authored-by: Eugen Maksymenko <emaksymenko@suse.com>
Co-authored-by: Rubén Torrero Marijnissen <rtorreromarijnissen@suse.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
elixir Pull requests that update Elixir code enhancement New feature or request
Development

Successfully merging this pull request may close these issues.

5 participants