-
Notifications
You must be signed in to change notification settings - Fork 461
Authorization
This is a description of the OBS authorization (who can do what) architecture.
A User or a Group can have many Role.
A Role can be global
[1] pry(main)> Role.where(global: true).map(&:title)
=> ["Admin", "Staff", "Moderator"]A Role can be local
[2] pry(main)> Role.where(global: false).map(&:title)
=> ["maintainer", "bugowner", "downloader", "reviewer", "reader"]That distinction will make more sense later, read on.
A Role has many StaticPermission. A StaticPermission is an "action" like:
[3] pry(main)> StaticPermission.all.map(&:title).first(3)
=> ["access", "change_package", "change_project"]The association between Project or Package and User or Group is called Relationship
- A
Projector aPackagecan have manyRelationship - A
Relationshipcan have oneUserorGroup - A
Relationshiphas oneRole(that is local)
Many aspects of a Project be configured by attaching Flags to it.
A Flag has a position, flag (name) and status
[4] pry(main)> Flag.last.slice(:position, :flag, :status)
=> {"position"=>2, "flag"=>"publish", "status"=>"disable"}
Two of those Flag configure authorization aspects of a Project.
If a Project has a Flag.where(flag: :access, status: :disable) then it's only accessible for the User or Group that have a Relationship with it.
If a Project has a Flag.where(flag: :sourceaccess, status: :disable) then files (sources) of all the Package in the Project are only accessible for the User or Group that have a Relationship with it.
With all of the above we can do the various authorization checks we do throughout the app.
if @user.roles.exists?(title: 'Admin')...if @user.roles.any? { |role| role.static_permissions.find_by(title: 'change_project') }
...
end[5] pry(main)> role = Role.find_by(title: 'maintainer'); nil
=> nil
[6] pry(main)> user = User.find_by(login: 'hennevogel'); nil
=> nil
[7] pry(main)> Project.find_by(name: 'home:hennevogel').relationships.exists?(role_id: role.id, user_id: user.id)
=> trueif project.flags.any? { |flag| flag.flag == 'sourceaccess' && flag.status == 'disable' }
...
endThis is slightly more complicated. We apply a default_scope to avoid instantiating Project that have an "access" Flag.
default_scope { where.not('projects.id' => Relationship.forbidden_project_ids) }
Where Relationship.forbidden_project_ids is a method that runs (and caches) a complicated query per User of all the Project with Flag.where(flag: :access, status: :disable) that they are NOT having a Relationship with.
Most of our pundit policies make use of the above checks too. Go read the pundit documentation to understand the rest.
- Development Environment Overview
- Development Environment Tips & Tricks
- Spec-Tips
- Code Style
- Rubocop
- Testing with VCR
- Test in kanku
- Authentication
- Authorization
- Autocomplete
- BS Requests
- Events
- ProjectLog
- Notifications
- Feature Toggles
- Build Results
- Attrib classes
- Flags
- The BackendPackage Cache
- Maintenance classes
- Cloud uploader
- Delayed Jobs
- Staging Workflow
- StatusHistory
- OBS API
- Owner Search
- Search
- Links
- Distributions
- Repository
- Data Migrations
- Package Versions
- next_rails
- Ruby Update
- Rails Profiling
- Remote Pairing Setup Guide
- Factory Dashboard
- osc
- Setup an OBS Development Environment on macOS
- Run OpenQA smoketest locally
- Responsive Guidelines
- Importing database dumps
- Problem Statement & Solution
- Kickoff New Stuff
- New Swagger API doc
- Documentation and Communication
- GitHub Actions
- Brakeman
- How to Introduce Software Design Patterns
- Query Objects
- Services
- View Components
- RFC: Core Components
- RFC: Decorator Pattern
- RFC: Backend models
- RFC: Hotwire Turbo Frames Pattern