132 lines
4.6 KiB
Go
132 lines
4.6 KiB
Go
// Package role defines the permission vocabulary that authorizes console and
|
|
// management behavior.
|
|
//
|
|
// Roles are rows in the roles table and their permissions live in
|
|
// role_permissions, so a tenant can define its own and authorization is
|
|
// resolved by the database rather than from a matrix held here. What belongs in
|
|
// this package is the closed set of permissions a role may be granted, plus the
|
|
// labels the console renders.
|
|
//
|
|
// Keep the permission list in step with the role_permissions_permission_check
|
|
// constraint in migration 0006: a name that is not in both places cannot be
|
|
// stored.
|
|
package role
|
|
|
|
// Permission is a capability granted by a role.
|
|
type Permission string
|
|
|
|
const (
|
|
// ReadConsole opens the management console. Self-service members lack it so
|
|
// that they are routed to their profile instead.
|
|
ReadConsole Permission = "console.read"
|
|
// ReadUsers lists a tenant's members and their roles.
|
|
ReadUsers Permission = "users.read"
|
|
// ManageApplications registers applications and configures their client
|
|
// credentials.
|
|
ManageApplications Permission = "applications.manage"
|
|
// ManageKeys issues and revokes API keys.
|
|
ManageKeys Permission = "keys.manage"
|
|
// ManageContracts imports OpenAPI contracts.
|
|
ManageContracts Permission = "contracts.manage"
|
|
// ManageUsers invites members and changes the roles and application grants
|
|
// of existing ones.
|
|
ManageUsers Permission = "users.manage"
|
|
// ManageRoles creates and edits the tenant's own roles. Kept separate from
|
|
// ManageUsers because defining roles is what defines privilege.
|
|
ManageRoles Permission = "roles.manage"
|
|
// ManageTenants creates tenants and administers the installation.
|
|
ManageTenants Permission = "tenants.manage"
|
|
// EditProfile changes one's own display name and picture.
|
|
EditProfile Permission = "profile.edit"
|
|
)
|
|
|
|
// ordered lists every permission from most to least sensitive. The order is the
|
|
// one the console renders checkboxes in.
|
|
var ordered = []Permission{
|
|
ManageTenants,
|
|
ManageRoles,
|
|
ManageUsers,
|
|
ManageApplications,
|
|
ManageKeys,
|
|
ManageContracts,
|
|
ReadUsers,
|
|
ReadConsole,
|
|
EditProfile,
|
|
}
|
|
|
|
var known = map[Permission]bool{
|
|
ReadConsole: true,
|
|
ReadUsers: true,
|
|
ManageApplications: true,
|
|
ManageKeys: true,
|
|
ManageContracts: true,
|
|
ManageUsers: true,
|
|
ManageRoles: true,
|
|
ManageTenants: true,
|
|
EditProfile: true,
|
|
}
|
|
|
|
// Entry describes a permission for the console and for API clients.
|
|
type Entry struct {
|
|
Value string `json:"value"`
|
|
Label string `json:"label"`
|
|
Description string `json:"description"`
|
|
}
|
|
|
|
var details = map[Permission]struct{ label, description string }{
|
|
ReadConsole: {"Read console", "Open the management console and pick tenants."},
|
|
ReadUsers: {"Read members", "List the members of a tenant and the roles they hold."},
|
|
ManageApplications: {"Manage applications", "Register applications and configure client credentials."},
|
|
ManageKeys: {"Manage API keys", "Issue and revoke API keys."},
|
|
ManageContracts: {"Manage contracts", "Import OpenAPI contracts and their endpoints."},
|
|
ManageUsers: {"Manage members", "Invite members and change their roles and application grants."},
|
|
ManageRoles: {"Manage roles", "Create and edit the roles of this tenant."},
|
|
ManageTenants: {"Manage tenants", "Create tenants and administer the installation."},
|
|
EditProfile: {"Edit own profile", "Change one's own display name and picture."},
|
|
}
|
|
|
|
// Permissions returns every permission in display order.
|
|
func Permissions() []Permission {
|
|
result := make([]Permission, len(ordered))
|
|
copy(result, ordered)
|
|
return result
|
|
}
|
|
|
|
// Parse validates a submitted permission name. Unknown values are rejected so
|
|
// that a crafted payload cannot invent capabilities.
|
|
func Parse(value string) (Permission, bool) {
|
|
candidate := Permission(value)
|
|
if !known[candidate] {
|
|
return "", false
|
|
}
|
|
return candidate, true
|
|
}
|
|
|
|
// Valid reports whether the value names a permission.
|
|
func (p Permission) Valid() bool {
|
|
return known[p]
|
|
}
|
|
|
|
// Catalog returns every permission with a label and description so that the
|
|
// console and API clients never hardcode the list.
|
|
func Catalog() []Entry {
|
|
result := make([]Entry, 0, len(ordered))
|
|
for _, permission := range ordered {
|
|
detail := details[permission]
|
|
result = append(result, Entry{
|
|
Value: string(permission),
|
|
Label: detail.label,
|
|
Description: detail.description,
|
|
})
|
|
}
|
|
return result
|
|
}
|
|
|
|
// Values returns every permission as strings, for use as a SQL array parameter.
|
|
func Values() []string {
|
|
result := make([]string, 0, len(ordered))
|
|
for _, permission := range ordered {
|
|
result = append(result, string(permission))
|
|
}
|
|
return result
|
|
}
|