Documentation
¶
Overview ¶
Package auth handles UI accounts: password login and cookie sessions. Who may call what is a Policy given by the services; what is recorded goes to an Auditor.
Index ¶
- Constants
- func Actor(ctx context.Context) string
- func HashPassword(ctx context.Context, password string) (string, error)
- func NewUser(ctx context.Context, username, password string, role store.Role, now time.Time) (store.User, error)
- func NormalizeUsername(u string) string
- func Protect(apiPrefixes []string, next http.Handler) http.Handler
- func RoleFromProto(r netprobev1.Role) (store.Role, bool)
- func RoleProto(r store.Role) netprobev1.Role
- func UserProto(u store.User) *netprobev1.User
- func ValidatePassword(password, username string) error
- func ValidateUsername(u string) error
- func VerifyPassword(ctx context.Context, password, encoded string) (bool, error)
- type Auditor
- type Policy
- type Principal
- type Service
- func (s *Service) Authenticate(ctx context.Context, h http.Header) (Principal, error)
- func (s *Service) ChangePassword(ctx context.Context, req *connect.Request[netprobev1.ChangePasswordRequest]) (_ *connect.Response[netprobev1.ChangePasswordResponse], err error)
- func (s *Service) Interceptor() connect.UnaryInterceptorFunc
- func (s *Service) Login(ctx context.Context, req *connect.Request[netprobev1.LoginRequest]) (res *connect.Response[netprobev1.LoginResponse], err error)
- func (s *Service) Logout(ctx context.Context, req *connect.Request[netprobev1.LogoutRequest]) (*connect.Response[netprobev1.LogoutResponse], error)
- func (s *Service) Me(ctx context.Context, req *connect.Request[netprobev1.MeRequest]) (*connect.Response[netprobev1.MeResponse], error)
- func (s *Service) Purge(ctx context.Context)
- type Store
Constants ¶
const ( // A session ends after this long without a request... IdleTimeout = 12 * time.Hour // ...and after this long anyway. MaxAge = 7 * 24 * time.Hour )
const (
MinPasswordLen = 8 // characters
)
Variables ¶
This section is empty.
Functions ¶
func HashPassword ¶
HashPassword returns an argon2id PHC string.
func NewUser ¶
func NewUser(ctx context.Context, username, password string, role store.Role, now time.Time) (store.User, error)
NewUser validates and hashes a new account.
func NormalizeUsername ¶
NormalizeUsername is how usernames are compared and stored.
func Protect ¶
Protect adds security headers and refuses cross-site requests that change state (Sec-Fetch-Site and Origin checks), on top of the SameSite=Strict cookie.
func RoleFromProto ¶
func RoleFromProto(r netprobev1.Role) (store.Role, bool)
RoleFromProto returns false for an unknown role.
func UserProto ¶
func UserProto(u store.User) *netprobev1.User
UserProto never includes the password hash.
func ValidatePassword ¶
ValidatePassword checks the password policy.
func ValidateUsername ¶
ValidateUsername checks a username, already lowercased.
Types ¶
type Auditor ¶
type Auditor interface {
Record(ctx context.Context, actor, action string, err error, clientIP string, req proto.Message)
}
Auditor records sign ins, sign outs, password changes and refused calls.
type Service ¶
type Service struct {
Store Store
// Secure cookies (HTTPS or localhost). Only false for plain HTTP tests.
SecureCookie bool
Allow Policy
Audit Auditor
// contains filtered or unexported fields
}
Service implements AuthService and checks the session of API requests.
func (*Service) Authenticate ¶
Authenticate returns the user of the session cookie in h.
func (*Service) ChangePassword ¶
func (s *Service) ChangePassword(ctx context.Context, req *connect.Request[netprobev1.ChangePasswordRequest]) (_ *connect.Response[netprobev1.ChangePasswordResponse], err error)
func (*Service) Interceptor ¶
func (s *Service) Interceptor() connect.UnaryInterceptorFunc
Interceptor requires a session on every call and asks the policy.
func (*Service) Login ¶
func (s *Service) Login(ctx context.Context, req *connect.Request[netprobev1.LoginRequest]) (res *connect.Response[netprobev1.LoginResponse], err error)
func (*Service) Logout ¶
func (s *Service) Logout(ctx context.Context, req *connect.Request[netprobev1.LogoutRequest]) (*connect.Response[netprobev1.LogoutResponse], error)
func (*Service) Me ¶
func (s *Service) Me(ctx context.Context, req *connect.Request[netprobev1.MeRequest]) (*connect.Response[netprobev1.MeResponse], error)
type Store ¶
type Store interface {
UserByName(ctx context.Context, username string) (store.User, error)
CreateSession(ctx context.Context, s store.Session) error
SessionUser(ctx context.Context, tokenHash []byte, now, idleSince time.Time) (store.Session, store.User, error)
TouchSession(ctx context.Context, tokenHash []byte, now time.Time) error
DeleteSession(ctx context.Context, tokenHash []byte) error
SetPassword(ctx context.Context, id uuid.UUID, hash string, keep []byte, now time.Time) error
PurgeSessions(ctx context.Context, now, idleSince time.Time) (int64, error)
}
Store is what auth needs from the database.