ntfy/auth/auth.go

122 lines
4.1 KiB
Go
Raw Normal View History

2022-01-23 06:02:16 +01:00
package auth
2022-01-31 17:44:58 +01:00
import (
"errors"
"regexp"
)
2022-01-23 06:02:16 +01:00
2022-01-23 06:54:18 +01:00
// Auther is a generic interface to implement password-based authentication and authorization
type Auther interface {
2022-01-26 04:30:53 +01:00
// Authenticate checks username and password and returns a user if correct. The method
// returns in constant-ish time, regardless of whether the user exists or the password is
// correct or incorrect.
Authenticate(username, password string) (*User, error)
// Authorize returns nil if the given user has access to the given topic using the desired
// permission. The user param may be nil to signal an anonymous user.
2022-01-23 06:02:16 +01:00
Authorize(user *User, topic string, perm Permission) error
}
2022-01-26 04:30:53 +01:00
// Manager is an interface representing user and access management
2022-01-23 06:54:18 +01:00
type Manager interface {
2022-01-26 04:30:53 +01:00
// AddUser adds a user with the given username, password and role. The password should be hashed
// before it is stored in a persistence layer.
2022-01-23 06:54:18 +01:00
AddUser(username, password string, role Role) error
2022-01-26 04:30:53 +01:00
// RemoveUser deletes the user with the given username. The function returns nil on success, even
// if the user did not exist in the first place.
2022-01-23 06:54:18 +01:00
RemoveUser(username string) error
2022-01-26 04:30:53 +01:00
// Users returns a list of users. It always also returns the Everyone user ("*").
2022-01-24 05:02:39 +01:00
Users() ([]*User, error)
2022-01-26 04:30:53 +01:00
// User returns the user with the given username if it exists, or ErrNotFound otherwise.
// You may also pass Everyone to retrieve the anonymous user and its Grant list.
2022-01-24 05:02:39 +01:00
User(username string) (*User, error)
2022-01-26 04:30:53 +01:00
// ChangePassword changes a user's password
2022-01-23 06:54:18 +01:00
ChangePassword(username, password string) error
2022-01-26 04:30:53 +01:00
// ChangeRole changes a user's role. When a role is changed from RoleUser to RoleAdmin,
// all existing access control entries (Grant) are removed, since they are no longer needed.
2022-01-23 21:30:30 +01:00
ChangeRole(username string, role Role) error
2022-01-26 04:30:53 +01:00
// AllowAccess adds or updates an entry in th access control list for a specific user. It controls
2022-01-31 17:44:58 +01:00
// read/write access to a topic. The parameter topicPattern may include wildcards (*).
AllowAccess(username string, topicPattern string, read bool, write bool) error
2022-01-26 04:30:53 +01:00
// ResetAccess removes an access control list entry for a specific username/topic, or (if topic is
2022-01-31 17:44:58 +01:00
// empty) for an entire user. The parameter topicPattern may include wildcards (*).
ResetAccess(username string, topicPattern string) error
2022-01-26 04:30:53 +01:00
// DefaultAccess returns the default read/write access if no access control entry matches
DefaultAccess() (read bool, write bool)
2022-01-23 06:54:18 +01:00
}
2022-01-26 04:30:53 +01:00
// User is a struct that represents a user
2022-01-23 06:02:16 +01:00
type User struct {
2022-01-24 05:02:39 +01:00
Name string
2022-01-26 03:57:28 +01:00
Hash string // password hash (bcrypt)
2022-01-24 05:02:39 +01:00
Role Role
Grants []Grant
}
2022-01-26 04:30:53 +01:00
// Grant is a struct that represents an access control entry to a topic
2022-01-24 05:02:39 +01:00
type Grant struct {
2022-01-31 17:47:30 +01:00
TopicPattern string // May include wildcard (*)
AllowRead bool
AllowWrite bool
2022-01-23 06:02:16 +01:00
}
2022-01-26 04:30:53 +01:00
// Permission represents a read or write permission to a topic
2022-01-23 06:02:16 +01:00
type Permission int
2022-01-26 04:30:53 +01:00
// Permissions to a topic
2022-01-23 06:02:16 +01:00
const (
PermissionRead = Permission(1)
PermissionWrite = Permission(2)
)
2022-01-26 04:30:53 +01:00
// Role represents a user's role, either admin or regular user
2022-01-23 06:02:16 +01:00
type Role string
2022-01-26 04:30:53 +01:00
// User roles
2022-01-23 06:02:16 +01:00
const (
2022-01-24 06:54:28 +01:00
RoleAdmin = Role("admin")
RoleUser = Role("user")
RoleAnonymous = Role("anonymous")
2022-01-23 06:02:16 +01:00
)
2022-01-26 04:30:53 +01:00
// Everyone is a special username representing anonymous users
2022-01-24 06:54:28 +01:00
const (
Everyone = "*"
)
2022-01-23 21:30:30 +01:00
2022-01-31 17:44:58 +01:00
var (
allowedUsernameRegex = regexp.MustCompile(`^[-_.@a-zA-Z0-9]+$`) // Does not include Everyone (*)
allowedTopicPatternRegex = regexp.MustCompile(`^[-_*A-Za-z0-9]{1,64}$`) // Adds '*' for wildcards!
)
2022-01-26 04:30:53 +01:00
// AllowedRole returns true if the given role can be used for new users
2022-01-23 21:30:30 +01:00
func AllowedRole(role Role) bool {
return role == RoleUser || role == RoleAdmin
}
2022-01-31 17:44:58 +01:00
// AllowedUsername returns true if the given username is valid
func AllowedUsername(username string) bool {
return allowedUsernameRegex.MatchString(username)
}
// AllowedTopicPattern returns true if the given topic pattern is valid; this includes the wildcard character (*)
func AllowedTopicPattern(username string) bool {
return allowedTopicPatternRegex.MatchString(username)
}
2022-01-26 04:30:53 +01:00
// Error constants used by the package
2022-01-24 05:02:39 +01:00
var (
2022-01-26 03:57:28 +01:00
ErrUnauthenticated = errors.New("unauthenticated")
ErrUnauthorized = errors.New("unauthorized")
ErrInvalidArgument = errors.New("invalid argument")
ErrNotFound = errors.New("not found")
2022-01-24 05:02:39 +01:00
)