authz

package
v0.0.0-...-a8e4d9d Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 7, 2020 License: AGPL-3.0 Imports: 8 Imported by: 0

Documentation

Overview

Package authz handles authorization logic for different entities in Harrow. Its purpose is to answer questions such as "Can this user edit that project?".

Basics

This package implements role-based authorization. The following terms related to role-based authorization are used throughout this text:

Action: something a user can do ("create")
Subject:  the thing subjected to the user's action ("project")
Capability: a combination of an action and a subject ("create-project")
Role: a set of capabilities ([]string{"create-project", "create-task", ...})

A user is authorized to perform an action if she possesses the right Capability. The list of Capabilities a user possesses is determined by her roles. A user can possibly have many roles, as determined by the authorization context. The set of all Capabilities a user possesses in relation to a Subject is the union of all her roles.

The context for authorization is determined by the user's relation to the Subject. Roles are determined by inspecting this context.

Implementation

The definitions above pose the question how a user's roles are determined. Most of the roles in Harrow are related to membership in a project or organization (e.g. ProjectOwner, OrganizationMember, etc). When asking for authorization directly on a project or organization, the role can easily be determined by looking at existing project or organization memberships.

Subjects that belong to a project need to expose their relation with a project in a way that allows authz to find the associated project. Likewise the relation to an organization, associated user and the owner of the Subject need to be exposed. The authz package defines several interfaces for this purpose: Subject, BelongsToProject, BelongsToUser, BelongsToOrganization, and Ownable.

Since not every Subject is associated with a project, organization or user, the implemenation of these interfaces is optional. Authz checks whether the Subject implements any of these interfaces and loads the respective entities for each implemented interface.

Authz first tries to load all the entities associated with the Subject and then looks at them to determine the user's roles. Once this is done, the requested Capability is checked against the Capabilities provided by all the roles.

Example (MinimalImplementation)

This example shows how to make an object compatible with authz.

package main

import (
	"fmt"

	"github.com/harrowio/harrow/authz"
	"github.com/harrowio/harrow/config"
)

type Foo struct{}

// AuthorizationName supplies the name of the authz.Subject for use
// in capablities.
func (self *Foo) AuthorizationName() string { return "foo" }

type FooOwner struct{}

// Capabilities implements authz.Role by returning the list of
// capabilities for this role.
func (self *FooOwner) Capabilities() []string {
	return []string{"delete-foo", "update-foo"}
}

// This example shows how to make an object compatible with authz.
func main() {
	role := &FooOwner{}
	service := authz.NewService(nil, nil, config.GetConfig())

	// authz doesn't know anything about FooOwner
	service.AddRole(role)

	subject := &Foo{}

	allowed, err := service.Can("update", subject)
	if err != nil {
		fmt.Printf("service.Can(%q, %#v): %s\n", "update", subject, err)
	}

	if !allowed {
		fmt.Printf("%T cannot update %T\n", role, subject)
	} else {
		fmt.Printf("%T can update %T\n", role, subject)
	}

}
Output:

*authz_test.FooOwner can update *authz_test.Foo

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrCapabilityMissing      = &Error{reason: "capability_missing"}
	ErrNoAuthorizationDefined = &Error{reason: "no_authorization_defined"}
	ErrBlocked                = &Error{reason: "blocked"}
)
View Source
var (
	BasicCapabilities = func() map[string]bool {
		return map[string]bool{
			"read-public":                             true,
			"create-session":                          true,
			domain.CapabilityValidate + "-session":    true,
			domain.CapabilitySignUp + "-user":         true,
			domain.CapabilityCreate + "-organization": true,
		}
	}
)

Functions

func NewService

func NewService(tx *sqlx.Tx, currentUser *domain.User, c *config.Config) *txService

Types

type BelongsToOrganization

type BelongsToOrganization interface {
	FindOrganization(store domain.OrganizationStore) (*domain.Organization, error)
}

type BelongsToProject

type BelongsToProject interface {
	FindProject(store domain.ProjectStore) (*domain.Project, error)
}

type BelongsToUser

type BelongsToUser interface {
	FindUser(store domain.UserStore) (*domain.User, error)
}

type Error

type Error struct {
	HaveCapabilities  map[string]bool
	MissingCapability string
	// contains filtered or unexported fields
}

func NewMissingCapabilityError

func NewMissingCapabilityError(haveCapabilities map[string]bool, missingCapability string) *Error

func (*Error) Error

func (e *Error) Error() string

func (*Error) Internal

func (e *Error) Internal() error

func (*Error) Reason

func (e *Error) Reason() string

type Ownable

type Ownable interface {
	OwnedBy(user *domain.User) bool
}

type Role

type Role interface {
	// Capabilities returns the list of capabilities possessed by this
	// role.  A capability should take the form of <VERB>-<SUBJECT-NAME>,
	// for example "read-project".
	//
	// Verbs understood by Service are: "create", "read", "update", "archive".
	Capabilities() []string
}

A Role is any source of capabilities.

type Service

type Service interface {
	CanRead(thing interface{}) (bool, error)
	CanCreate(thing interface{}) (bool, error)
	CanUpdate(thing interface{}) (bool, error)
	CanArchive(thing interface{}) (bool, error)
	Can(action string, thing interface{}) (bool, error)
	CapabilitiesBySubject() map[string][]string

	Log() logger.Logger
	SetLogger(logger.Logger)
}

type Subject

type Subject interface {
	// AuthorizationName returns name for this subject to be used
	// in capabilities.  The value returned by this function is used
	// to construct the capability name to check against.
	AuthorizationName() string
}

A Subject is anything against which capabilities can be checked.

type UserBlockStore

type UserBlockStore interface {
	UserIsBlocked(userUuid string) (bool, error)
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL