mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 19:21:50 +00:00
Followup from https://github.com/sourcegraph/sourcegraph/pull/63941. I forgot to make it so site admins could list org members in that PR. As for the new ability for site admins to see user and org settings: Site admins could already add themselves to orgs as members and see settings that way. I considered still keeping it stricter, but it is valuable for site admins to be able to view settings to help users troubleshoot. ## Test plan In dotcom mode, as a site admin, view a user or org (that the site admin is not a member of). Confirm that the settings can be viewed.
146 lines
4.8 KiB
Go
146 lines
4.8 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/sourcegraph/sourcegraph/internal/actor"
|
|
"github.com/sourcegraph/sourcegraph/internal/database"
|
|
"github.com/sourcegraph/sourcegraph/internal/errcode"
|
|
"github.com/sourcegraph/sourcegraph/internal/types"
|
|
"github.com/sourcegraph/sourcegraph/lib/errors"
|
|
)
|
|
|
|
var ErrMustBeSiteAdmin = errors.New("must be site admin")
|
|
var ErrMustBeSiteAdminOrSameUser = &InsufficientAuthorizationError{"must be authenticated as the authorized user or site admin"}
|
|
|
|
// CheckCurrentUserIsSiteAdmin returns an error if the current user is NOT a site admin.
|
|
func CheckCurrentUserIsSiteAdmin(ctx context.Context, db database.DB) error {
|
|
if actor.FromContext(ctx).IsInternal() {
|
|
return nil
|
|
}
|
|
user, err := CurrentUser(ctx, db)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if user == nil {
|
|
return ErrNotAuthenticated
|
|
}
|
|
if !user.SiteAdmin {
|
|
return ErrMustBeSiteAdmin
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// CheckUserIsSiteAdmin returns an error if the user is NOT a site admin.
|
|
func CheckUserIsSiteAdmin(ctx context.Context, db database.DB, userID int32) error {
|
|
if actor.FromContext(ctx).IsInternal() {
|
|
return nil
|
|
}
|
|
user, err := db.Users().GetByID(ctx, userID)
|
|
if err != nil {
|
|
if errcode.IsNotFound(err) || err == database.ErrNoCurrentUser {
|
|
return ErrNotAuthenticated
|
|
}
|
|
return err
|
|
}
|
|
if !user.SiteAdmin {
|
|
return ErrMustBeSiteAdmin
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// InsufficientAuthorizationError is an error that occurs when the authentication is technically valid
|
|
// (e.g., the token is not expired) but does not yield a user with privileges to perform a certain
|
|
// action.
|
|
type InsufficientAuthorizationError struct {
|
|
Message string
|
|
}
|
|
|
|
func (e *InsufficientAuthorizationError) Error() string { return e.Message }
|
|
func (e *InsufficientAuthorizationError) Unauthorized() bool { return true }
|
|
|
|
// CheckSiteAdminOrSameUser returns an error if the user is NEITHER (1) a
|
|
// site admin NOR (2) the user specified by subjectUserID.
|
|
//
|
|
// It is used when an action on a user can be performed by site admins and the
|
|
// user themselves, but nobody else.
|
|
//
|
|
// Returns an error without the name of the given user.
|
|
func CheckSiteAdminOrSameUser(ctx context.Context, db database.DB, subjectUserID int32) error {
|
|
a := actor.FromContext(ctx)
|
|
return CheckSiteAdminOrSameUserFromActor(a, db, subjectUserID)
|
|
}
|
|
|
|
// CheckSameUser returns an error if the user is not the user specified by subjectUserID. It is used
|
|
// for actions that can ONLY be performed by that user. In most cases, site admins should also be
|
|
// able to perform the action, and you should use CheckSiteAdminOrSameUser instead.
|
|
func CheckSameUser(ctx context.Context, subjectUserID int32) error {
|
|
a := actor.FromContext(ctx)
|
|
if a.IsInternal() || (a.IsAuthenticated() && a.UID == subjectUserID) {
|
|
return nil
|
|
}
|
|
return &InsufficientAuthorizationError{Message: fmt.Sprintf("must be authenticated as user with id %d", subjectUserID)}
|
|
}
|
|
|
|
// CurrentUser gets the current authenticated user
|
|
// It returns nil, nil if no user is found
|
|
func CurrentUser(ctx context.Context, db database.DB) (*types.User, error) {
|
|
user, err := db.Users().GetByCurrentAuthUser(ctx)
|
|
if err != nil {
|
|
if errcode.IsNotFound(err) || err == database.ErrNoCurrentUser {
|
|
return nil, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
return user, nil
|
|
}
|
|
|
|
// CheckCurrentActorIsSiteAdmin returns an error if the current user derived from
|
|
// actor is NOT a site admin.
|
|
func CheckCurrentActorIsSiteAdmin(a *actor.Actor, db database.DB) error {
|
|
if a.IsInternal() {
|
|
return nil
|
|
}
|
|
// If actor already contains a user, then no DB query will be made. Background
|
|
// context here is fine, because it is used only for a DB query.
|
|
user, err := a.User(context.Background(), db.Users())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if user == nil {
|
|
return ErrNotAuthenticated
|
|
}
|
|
if !user.SiteAdmin {
|
|
return ErrMustBeSiteAdmin
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// CheckSiteAdminOrSameUserFromActor returns an error if the user derived from actor is
|
|
// NEITHER (1) a site admin NOR (2) the user specified by subjectUserID.
|
|
//
|
|
// It is used when an action on a user can be performed by site admins and the
|
|
// user themselves, but nobody else.
|
|
//
|
|
// Returns an error without the name of the given user.
|
|
func CheckSiteAdminOrSameUserFromActor(a *actor.Actor, db database.DB, subjectUserID int32) error {
|
|
if a.IsInternal() || (a.IsAuthenticated() && a.UID == subjectUserID) {
|
|
return nil
|
|
}
|
|
isSiteAdminErr := CheckCurrentActorIsSiteAdmin(a, db)
|
|
if isSiteAdminErr == nil {
|
|
return nil
|
|
}
|
|
return ErrMustBeSiteAdminOrSameUser
|
|
}
|
|
|
|
// CheckSameUserFromActor returns an error if the user derived from actor is not the user
|
|
// specified by subjectUserID.
|
|
func CheckSameUserFromActor(a *actor.Actor, subjectUserID int32) error {
|
|
if a.IsInternal() || (a.IsAuthenticated() && a.UID == subjectUserID) {
|
|
return nil
|
|
}
|
|
return &InsufficientAuthorizationError{Message: fmt.Sprintf("must be authenticated as user with id %d", subjectUserID)}
|
|
}
|