-
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.
We actually have two architectures. The newer one is quickly explained, go read the pundit documentation.
Read on to understand the old system.
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 ``UserorGroup` 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.
- 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