-
Notifications
You must be signed in to change notification settings - Fork 441
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
Project
or aPackage
can have manyRelationship
- A
Relationship
can have oneUser
orGroup
- A
Relationship
has 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)
=> true
if project.flags.any? { |flag| flag.flag == 'sourceaccess' && flag.status == 'disable' }
...
end
This 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
- 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
- next_rails
- Ruby Update
- Rails Profiling
- Installing a local LDAP-server
- 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
- How to Introduce Software Design Patterns
- Query Objects
- Services
- View Components
- RFC: Core Components
- RFC: Decorator Pattern
- RFC: Backend models