88 lines
2.3 KiB
Go
88 lines
2.3 KiB
Go
package auth
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
)
|
|
|
|
// Permission represents a permission granted to a user.
|
|
//
|
|
// The nil permission represents any authenticated user.
|
|
type Permission func(user *AuthUser, r *http.Request) (ok Grant, err error)
|
|
|
|
// Grant represents an object that either grants or denies access for a certain permission
|
|
type Grant interface {
|
|
isGranted()
|
|
|
|
// Granted returns a boolean indicating if permission to the resource in question
|
|
// has been granted
|
|
Granted() bool
|
|
|
|
// Denied returns a string containing an error message to display to the user when permission is denied.
|
|
// When Granted() returns true, the behaviour is undefined.
|
|
Denied() string
|
|
}
|
|
|
|
// Bool2Grant returns a new grant that returns granted for the given boolean, and message as the denied message.
|
|
func Bool2Grant(granted bool, message string) Grant {
|
|
if granted {
|
|
return grantAllow{}
|
|
}
|
|
return grantDeny(message)
|
|
}
|
|
|
|
type grantAllow struct{}
|
|
|
|
func (grantAllow) isGranted() {}
|
|
func (grantAllow) Granted() bool { return true }
|
|
func (grantAllow) Denied() string { return "" }
|
|
|
|
type grantDeny string
|
|
|
|
func (grantDeny) isGranted() {}
|
|
func (g grantDeny) Granted() bool { return false }
|
|
func (g grantDeny) Denied() string {
|
|
if g == "" {
|
|
return "Forbidden"
|
|
}
|
|
return string(g)
|
|
}
|
|
|
|
// AllPermissions returns a new permission that checks if all the given permissions are set
|
|
func AllPermissions(clauses ...Permission) Permission {
|
|
return func(user *AuthUser, r *http.Request) (ok Grant, err error) {
|
|
for _, clause := range clauses {
|
|
perm, err := clause.Permit(user, r)
|
|
if err != nil {
|
|
return perm, err
|
|
}
|
|
if !perm.Granted() {
|
|
return perm, nil
|
|
}
|
|
}
|
|
|
|
// everything was fine
|
|
return grantAllow{}, nil
|
|
}
|
|
}
|
|
|
|
var errPermissionPanic = errors.New("permission: panic()")
|
|
|
|
// Permit checks if the given user has this permission.
|
|
func (perm Permission) Permit(user *AuthUser, r *http.Request) (ok Grant, err error) {
|
|
// if there is no permission, then we just check if there is some user
|
|
if perm == nil {
|
|
return Bool2Grant(user != nil, ""), nil
|
|
}
|
|
|
|
// recover any panic()ed permission call
|
|
// to prevent the handler from panic()ing
|
|
defer func() {
|
|
if p := recover(); p != nil {
|
|
ok = Bool2Grant(false, "unknown error")
|
|
err = errPermissionPanic
|
|
}
|
|
}()
|
|
|
|
return perm(user, r)
|
|
}
|