blob: 46011ab341288d424e9b229447489db4d333e563 [file] [log] [blame]
package twirp_auth
import (
"context"
"fmt"
"net/http"
"github.com/twitchtv/twirp"
"go.skia.org/infra/go/allowed"
"go.skia.org/infra/go/login"
)
/*
Helpers for working with Twirp.
*/
// AuthHelper provides methods for authenticating users.
type AuthHelper struct {
viewers allowed.Allow
editors allowed.Allow
admins allowed.Allow
getUser func(context.Context) string
}
// NewAuthHelper returns an AuthHelper instance which uses the given allow lists
// to control access. If the viewers list is nil, anyone is allowed to view.
// If the editors or admins lists are nil, nobody has permission for those
// actions.
func NewAuthHelper(viewers, editors, admins allowed.Allow) *AuthHelper {
return &AuthHelper{
viewers: viewers,
editors: editors,
admins: admins,
getUser: func(ctx context.Context) string {
session := login.GetSession(ctx)
if session == nil {
return ""
}
return session.Email
},
}
}
// GetViewer returns the email address of the logged-in user or an error if the
// user is not in the set of allowed viewers. Do not wrap the returned error, as
// it is used by Twirp.
func (h *AuthHelper) GetViewer(ctx context.Context) (string, error) {
email := h.getUser(ctx)
// Special case for viewers: if nil, anyone can view.
if h.viewers == nil || h.viewers.Member(email) {
return email, nil
}
return "", twirp.NewError(twirp.PermissionDenied, fmt.Sprintf("%q is not an authorized viewer", email))
}
// GetEditor returns the email address of the logged-in user or an error if the
// user is not in the set of allowed editors. Do not wrap the returned error, as
// it is used by Twirp.
func (h *AuthHelper) GetEditor(ctx context.Context) (string, error) {
email := h.getUser(ctx)
if h.editors != nil && h.editors.Member(email) {
return email, nil
}
return "", twirp.NewError(twirp.PermissionDenied, fmt.Sprintf("%q is not an authorized editor", email))
}
// GetAdmin returns the email address of the logged-in user or an error if the
// user is not in the set of allowed admins. Do not wrap the returned error, as
// it is used by Twirp.
func (h *AuthHelper) GetAdmin(ctx context.Context) (string, error) {
email := h.getUser(ctx)
if h.admins != nil && h.admins.Member(email) {
return email, nil
}
return "", twirp.NewError(twirp.PermissionDenied, fmt.Sprintf("%q is not an authorized admin", email))
}
// MockGetUserForTesting sets the function used to retrieve the logged-in user
// from the request context. This is intended to be used for testing only.
func (h *AuthHelper) MockGetUserForTesting(getUser func(context.Context) string) {
h.getUser = getUser
}
// Middleware wraps the given http.Handler with the login middleware required in
// order to use AuthHelper.
func Middleware(srv http.Handler) http.Handler {
return login.SessionMiddleware(srv)
}