Documentation
¶
Overview ¶
Package approle stores and resolves the roles principals hold in the applications of an organization (ADR-007).
An application role is one of the roles the application declares in its authz.AppVocabulary, assigned to a principal for one organization. The rules:
- Owners hold the application's top role (admin on the standard ladder) in every entitled application, implicitly, without a stored row. Admins and members hold only what is assigned to them.
- Nobody holds an application role by default, and an organization is entitled to no application unless the Service is given an entitlement source (WithEntitlementGrants, normally built from the marketplace by marketplace.ApproleOptions). A seat-licensed application caps how many principals may hold a role in it.
- Only active owners, admins and members can hold a role; collaborators and non-members cannot.
- Removing a member deletes their roles (organization.Service RemoveMember does this in its transaction). Deactivating a membership leaves the rows in place but EffectiveRoles ignores them until the membership is active again.
Index ¶
- Variables
- func TopRole(v authz.AppVocabulary) string
- type AppRole
- type AssignInput
- type EntitlementFunc
- type Grant
- type GrantsFunc
- type Option
- func EntitleAll(registry *authz.VocabularyRegistry) Option
- func WithAccessChangeSink(sink accesschange.Sink) Option
- func WithAuthzSyncer(syncer authz.RelationshipSyncer, mode authz.SyncMode) Option
- func WithEntitlementGrants(f GrantsFunc) Option
- func WithEntitlements(f EntitlementFunc) Option
- func WithLogger(l *slog.Logger) Option
- type Service
- func (s *Service) Assign(ctx context.Context, in AssignInput) (*AppRole, error)
- func (s *Service) AssignInTx(ctx context.Context, tx *ent.Tx, in AssignInput) (*AppRole, func(context.Context) error, error)
- func (s *Service) Change(ctx context.Context, in AssignInput) (*AppRole, error)
- func (s *Service) EffectiveRoles(ctx context.Context, principalID, organizationID uuid.UUID) (map[string]string, error)
- func (s *Service) EntitledApplications(ctx context.Context, organizationID uuid.UUID) ([]string, error)
- func (s *Service) ListForOrganization(ctx context.Context, organizationID uuid.UUID, application string) ([]*AppRole, error)
- func (s *Service) ListForPrincipal(ctx context.Context, organizationID, principalID uuid.UUID) ([]*AppRole, error)
- func (s *Service) Remove(ctx context.Context, organizationID, principalID uuid.UUID, application string, ...) error
- func (s *Service) RemoveForMember(ctx context.Context, organizationID, principalID uuid.UUID) (int, error)
- func (s *Service) Roles(application string) ([]string, error)
- func (s *Service) ValidateRoles(ctx context.Context, organizationID uuid.UUID, roles map[string]string) error
Constants ¶
This section is empty.
Variables ¶
var ( // ErrUnknownApplication means the application is not registered. ErrUnknownApplication = errors.New("approle: unknown application") // ErrUnknownRole means the role is not one the application declares. ErrUnknownRole = errors.New("approle: role not declared by the application") // ErrNotEntitled means the organization is not entitled to the // application. ErrNotEntitled = errors.New("approle: organization is not entitled to the application") // ErrNotMember means the principal has no active owner, admin or // member membership in the organization. ErrNotMember = errors.New("approle: principal is not an active owner, admin or member") // ErrNoSeats means every seat licensed for the application is already // held by a principal with a role in it. ErrNoSeats = errors.New("approle: no seats available for the application") // ErrAlreadyAssigned means the principal already has a role in the // application; use Change. ErrAlreadyAssigned = errors.New("approle: role already assigned") // ErrNotAssigned means the principal has no stored role in the // application. ErrNotAssigned = errors.New("approle: role not assigned") )
Errors returned by the service.
Functions ¶
func TopRole ¶
func TopRole(v authz.AppVocabulary) string
TopRole returns the highest role of a vocabulary: "admin" if it declares one, otherwise the role with the highest hierarchy level (ties broken by name for determinism).
Types ¶
type AppRole ¶
type AppRole struct {
ID uuid.UUID
PrincipalID uuid.UUID
OrganizationID uuid.UUID
Application string
Role string
AssignedBy *uuid.UUID
}
AppRole is a principal's stored role in one application of an organization.
type AssignInput ¶
type AssignInput struct {
OrganizationID uuid.UUID
PrincipalID uuid.UUID
Application string
Role string
// AssignedBy is the principal making the change. It may equal
// PrincipalID: assigning a role to oneself is allowed and logged.
AssignedBy uuid.UUID
}
AssignInput identifies a role to assign or change.
type EntitlementFunc ¶
type EntitlementFunc func(ctx context.Context, organizationID uuid.UUID, application string) (bool, error)
EntitlementFunc reports whether an organization is entitled to an application.
type Grant ¶
type Grant struct {
// SeatLimit caps the number of principals holding a role in the
// application. Nil means unlimited.
SeatLimit *int
}
Grant describes an organization's entitlement to one application.
type GrantsFunc ¶
GrantsFunc returns the applications an organization is entitled to, keyed by application identifier. One call answers for every application, so it is cheaper than an EntitlementFunc per application.
type Option ¶
type Option func(*Service)
Option configures a Service.
func EntitleAll ¶
func EntitleAll(registry *authz.VocabularyRegistry) Option
EntitleAll treats every registered application as entitled to every organization, with unlimited seats. It is for development and tests; without any entitlement option no organization is entitled to anything.
func WithAccessChangeSink ¶
func WithAccessChangeSink(sink accesschange.Sink) Option
WithAccessChangeSink announces the access changes the service records, a changed or removed application role, to sink after the transaction that recorded them commits (ADR-010). The records are written whether or not a sink is set.
func WithAuthzSyncer ¶
func WithAuthzSyncer(syncer authz.RelationshipSyncer, mode authz.SyncMode) Option
WithAuthzSyncer writes application roles to the authorization graph when syncer also implements authz.AppRoleSyncer; a syncer that does not is ignored, so any existing authz.RelationshipSyncer can be passed. In authz.SyncModeStrict a failed write is returned to the caller after the role was stored; in SyncModeEventual (the default) it is logged.
func WithEntitlementGrants ¶
func WithEntitlementGrants(f GrantsFunc) Option
WithEntitlementGrants sets the source of an organization's entitled applications and their seat limits. marketplace.ApproleOptions builds one from active subscriptions, licenses and the deployment's default entitlements.
func WithEntitlements ¶
func WithEntitlements(f EntitlementFunc) Option
WithEntitlements restricts roles to the applications f reports the organization is entitled to. It carries no seat limits; prefer WithEntitlementGrants, which takes precedence when both are set.
func WithLogger ¶
WithLogger sets the logger that records assignments.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service manages application roles.
func NewService ¶
NewService returns a Service that validates roles against the vocabularies in registry.
func (*Service) Assign ¶
Assign gives the principal a role in an application. It fails with ErrAlreadyAssigned if the principal already has one. When the application has a seat limit, counting the seats and inserting the role happen under a lock, so concurrent assignments cannot exceed the limit.
func (*Service) AssignInTx ¶
func (s *Service) AssignInTx(ctx context.Context, tx *ent.Tx, in AssignInput) (*AppRole, func(context.Context) error, error)
AssignInTx gives the principal a role inside the caller's transaction, for flows that create the membership and its roles together, such as accepting an invitation. The principal's membership may be created in tx, uncommitted. Seat limits are enforced under the same lock Assign takes. It returns a function to call after tx commits, which audits the assignment and writes it to the authorization graph; its error is the sync error Assign would return.
func (*Service) Change ¶
Change sets a different role for a principal who already has one. It fails with ErrNotAssigned if there is none.
func (*Service) EffectiveRoles ¶
func (s *Service) EffectiveRoles(ctx context.Context, principalID, organizationID uuid.UUID) (map[string]string, error)
EffectiveRoles returns the principal's role in each application of the organization, keyed by application. An application absent from the map is one the principal may not open. A non-member, an inactive member and a collaborator get an empty map. An owner holds the top role of every entitled registered application; anyone else holds their stored roles for entitled applications. If both apply, the higher role wins.
func (*Service) EntitledApplications ¶
func (s *Service) EntitledApplications(ctx context.Context, organizationID uuid.UUID) ([]string, error)
EntitledApplications lists the registered applications the organization is entitled to, sorted. A role picker offers these.
func (*Service) ListForOrganization ¶
func (s *Service) ListForOrganization(ctx context.Context, organizationID uuid.UUID, application string) ([]*AppRole, error)
ListForOrganization lists the stored roles in an organization, ordered by application. A non-empty application limits the list to it.
func (*Service) ListForPrincipal ¶
func (s *Service) ListForPrincipal(ctx context.Context, organizationID, principalID uuid.UUID) ([]*AppRole, error)
ListForPrincipal lists the stored roles a principal holds in an organization, ordered by application. Implicit owner roles are not included; see EffectiveRoles.
func (*Service) Remove ¶
func (s *Service) Remove(ctx context.Context, organizationID, principalID uuid.UUID, application string, removedBy uuid.UUID) error
Remove deletes the principal's role in an application. It fails with ErrNotAssigned if there is none.
func (*Service) RemoveForMember ¶
func (s *Service) RemoveForMember(ctx context.Context, organizationID, principalID uuid.UUID) (int, error)
RemoveForMember deletes every role the principal holds in the organization and reports how many it deleted. organization.Service does the same inside its RemoveMember transaction; this is for callers that remove access another way.
func (*Service) Roles ¶
Roles returns the roles an application declares, lowest first, for role pickers.
func (*Service) ValidateRoles ¶
func (s *Service) ValidateRoles(ctx context.Context, organizationID uuid.UUID, roles map[string]string) error
ValidateRoles checks roles, a map from application identifier to role, against the organization: each application must be registered, declare the role, and be one the organization is entitled to. It does not check membership or seats, so it can validate the roles of an invitation before the invitee is a member.