mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
AuthZ: Extend /api/search to work with self-contained permissions (#70749)
* Search sql filter draft, unfinished * Search works for empty roles * Add current AuthModule to SignedInUser * clean up, changes to the search * Use constant prefixes * Change AuthModule to AuthenticatedBy * Add tests for using the permissions from the SignedInUser * Refactor and simplify code * Fix sql generation for pg and mysql * Fixes, clean up * Add test for empty permission list * Fix * Fix any vs all in case of edit permission * Update pkg/services/authn/authn.go Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com> * Update pkg/services/sqlstore/permissions/dashboard_test.go Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com> * Fixes, changes based on the review --------- Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com>
This commit is contained in:
@@ -76,13 +76,13 @@ func (s *UserSync) SyncUserHook(ctx context.Context, id *authn.Identity, _ *auth
|
||||
// Does user exist in the database?
|
||||
usr, userAuth, errUserInDB := s.getUser(ctx, id)
|
||||
if errUserInDB != nil && !errors.Is(errUserInDB, user.ErrUserNotFound) {
|
||||
s.log.FromContext(ctx).Error("Failed to fetch user", "error", errUserInDB, "auth_module", id.AuthModule, "auth_id", id.AuthID)
|
||||
s.log.FromContext(ctx).Error("Failed to fetch user", "error", errUserInDB, "auth_module", id.AuthenticatedBy, "auth_id", id.AuthID)
|
||||
return errSyncUserInternal.Errorf("unable to retrieve user")
|
||||
}
|
||||
|
||||
if errors.Is(errUserInDB, user.ErrUserNotFound) {
|
||||
if !id.ClientParams.AllowSignUp {
|
||||
s.log.FromContext(ctx).Warn("Failed to create user, signup is not allowed for module", "auth_module", id.AuthModule, "auth_id", id.AuthID)
|
||||
s.log.FromContext(ctx).Warn("Failed to create user, signup is not allowed for module", "auth_module", id.AuthenticatedBy, "auth_id", id.AuthID)
|
||||
return errUserSignupDisabled.Errorf("%w", login.ErrSignupNotAllowed)
|
||||
}
|
||||
|
||||
@@ -90,13 +90,13 @@ func (s *UserSync) SyncUserHook(ctx context.Context, id *authn.Identity, _ *auth
|
||||
var errCreate error
|
||||
usr, errCreate = s.createUser(ctx, id)
|
||||
if errCreate != nil {
|
||||
s.log.FromContext(ctx).Error("Failed to create user", "error", errCreate, "auth_module", id.AuthModule, "auth_id", id.AuthID)
|
||||
s.log.FromContext(ctx).Error("Failed to create user", "error", errCreate, "auth_module", id.AuthenticatedBy, "auth_id", id.AuthID)
|
||||
return errSyncUserInternal.Errorf("unable to create user")
|
||||
}
|
||||
} else {
|
||||
// update user
|
||||
if errUpdate := s.updateUserAttributes(ctx, usr, id, userAuth); errUpdate != nil {
|
||||
s.log.FromContext(ctx).Error("Failed to update user", "error", errUpdate, "auth_module", id.AuthModule, "auth_id", id.AuthID)
|
||||
s.log.FromContext(ctx).Error("Failed to update user", "error", errUpdate, "auth_module", id.AuthenticatedBy, "auth_id", id.AuthID)
|
||||
return errSyncUserInternal.Errorf("unable to update user")
|
||||
}
|
||||
}
|
||||
@@ -174,7 +174,7 @@ func (s *UserSync) EnableDisabledUserHook(ctx context.Context, identity *authn.I
|
||||
}
|
||||
|
||||
func (s *UserSync) upsertAuthConnection(ctx context.Context, userID int64, identity *authn.Identity, createConnection bool) error {
|
||||
if identity.AuthModule == "" {
|
||||
if identity.AuthenticatedBy == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ func (s *UserSync) upsertAuthConnection(ctx context.Context, userID int64, ident
|
||||
if createConnection {
|
||||
return s.authInfoService.SetAuthInfo(ctx, &login.SetAuthInfoCommand{
|
||||
UserId: userID,
|
||||
AuthModule: identity.AuthModule,
|
||||
AuthModule: identity.AuthenticatedBy,
|
||||
AuthId: identity.AuthID,
|
||||
OAuthToken: identity.OAuthToken,
|
||||
})
|
||||
@@ -194,13 +194,13 @@ func (s *UserSync) upsertAuthConnection(ctx context.Context, userID int64, ident
|
||||
return s.authInfoService.UpdateAuthInfo(ctx, &login.UpdateAuthInfoCommand{
|
||||
UserId: userID,
|
||||
AuthId: identity.AuthID,
|
||||
AuthModule: identity.AuthModule,
|
||||
AuthModule: identity.AuthenticatedBy,
|
||||
OAuthToken: identity.OAuthToken,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *UserSync) updateUserAttributes(ctx context.Context, usr *user.User, id *authn.Identity, userAuth *login.UserAuth) error {
|
||||
if errProtection := s.userProtectionService.AllowUserMapping(usr, id.AuthModule); errProtection != nil {
|
||||
if errProtection := s.userProtectionService.AllowUserMapping(usr, id.AuthenticatedBy); errProtection != nil {
|
||||
return errUserProtection.Errorf("user mapping not allowed: %w", errProtection)
|
||||
}
|
||||
// sync user info
|
||||
@@ -286,8 +286,8 @@ func (s *UserSync) createUser(ctx context.Context, id *authn.Identity) (*user.Us
|
||||
|
||||
func (s *UserSync) getUser(ctx context.Context, identity *authn.Identity) (*user.User, *login.UserAuth, error) {
|
||||
// Check auth info fist
|
||||
if identity.AuthID != "" && identity.AuthModule != "" {
|
||||
query := &login.GetAuthInfoQuery{AuthId: identity.AuthID, AuthModule: identity.AuthModule}
|
||||
if identity.AuthID != "" && identity.AuthenticatedBy != "" {
|
||||
query := &login.GetAuthInfoQuery{AuthId: identity.AuthID, AuthModule: identity.AuthenticatedBy}
|
||||
authInfo, errGetAuthInfo := s.authInfoService.GetAuthInfo(ctx, query)
|
||||
|
||||
if errGetAuthInfo != nil && !errors.Is(errGetAuthInfo, user.ErrUserNotFound) {
|
||||
@@ -307,7 +307,7 @@ func (s *UserSync) getUser(ctx context.Context, identity *authn.Identity) (*user
|
||||
// if the user connected to user auth does not exist try to clean it up
|
||||
if errors.Is(errGetByID, user.ErrUserNotFound) {
|
||||
if err := s.authInfoService.DeleteUserAuthInfo(ctx, authInfo.UserId); err != nil {
|
||||
s.log.FromContext(ctx).Error("Failed to clean up user auth", "error", err, "auth_module", identity.AuthModule, "auth_id", identity.AuthID)
|
||||
s.log.FromContext(ctx).Error("Failed to clean up user auth", "error", err, "auth_module", identity.AuthenticatedBy, "auth_id", identity.AuthID)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -322,8 +322,8 @@ func (s *UserSync) getUser(ctx context.Context, identity *authn.Identity) (*user
|
||||
var userAuth *login.UserAuth
|
||||
// Special case for generic oauth: generic oauth does not store authID,
|
||||
// so we need to find the user first then check for the userAuth connection by module and userID
|
||||
if identity.AuthModule == login.GenericOAuthModule {
|
||||
query := &login.GetAuthInfoQuery{AuthModule: identity.AuthModule, UserId: usr.ID}
|
||||
if identity.AuthenticatedBy == login.GenericOAuthModule {
|
||||
query := &login.GetAuthInfoQuery{AuthModule: identity.AuthenticatedBy, UserId: usr.ID}
|
||||
userAuth, err = s.authInfoService.GetAuthInfo(ctx, query)
|
||||
if err != nil && !errors.Is(err, user.ErrUserNotFound) {
|
||||
return nil, nil, err
|
||||
|
||||
@@ -268,12 +268,12 @@ func TestUserSync_SyncUserHook(t *testing.T) {
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
id: &authn.Identity{
|
||||
ID: "",
|
||||
AuthID: "2032",
|
||||
AuthModule: "oauth",
|
||||
Login: "test",
|
||||
Name: "test",
|
||||
Email: "test",
|
||||
ID: "",
|
||||
AuthID: "2032",
|
||||
AuthenticatedBy: "oauth",
|
||||
Login: "test",
|
||||
Name: "test",
|
||||
Email: "test",
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncUser: true,
|
||||
LookUpParams: login.UserLookupParams{
|
||||
@@ -286,13 +286,13 @@ func TestUserSync_SyncUserHook(t *testing.T) {
|
||||
},
|
||||
wantErr: false,
|
||||
wantID: &authn.Identity{
|
||||
ID: "user:1",
|
||||
AuthID: "2032",
|
||||
AuthModule: "oauth",
|
||||
Login: "test",
|
||||
Name: "test",
|
||||
Email: "test",
|
||||
IsGrafanaAdmin: ptrBool(false),
|
||||
ID: "user:1",
|
||||
AuthID: "2032",
|
||||
AuthenticatedBy: "oauth",
|
||||
Login: "test",
|
||||
Name: "test",
|
||||
Email: "test",
|
||||
IsGrafanaAdmin: ptrBool(false),
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncUser: true,
|
||||
LookUpParams: login.UserLookupParams{
|
||||
@@ -313,12 +313,12 @@ func TestUserSync_SyncUserHook(t *testing.T) {
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
id: &authn.Identity{
|
||||
ID: "",
|
||||
Login: "test",
|
||||
Name: "test",
|
||||
Email: "test",
|
||||
AuthModule: "oauth",
|
||||
AuthID: "2032",
|
||||
ID: "",
|
||||
Login: "test",
|
||||
Name: "test",
|
||||
Email: "test",
|
||||
AuthenticatedBy: "oauth",
|
||||
AuthID: "2032",
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncUser: true,
|
||||
LookUpParams: login.UserLookupParams{
|
||||
@@ -341,13 +341,13 @@ func TestUserSync_SyncUserHook(t *testing.T) {
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
id: &authn.Identity{
|
||||
ID: "",
|
||||
Login: "test_create",
|
||||
Name: "test_create",
|
||||
IsGrafanaAdmin: ptrBool(true),
|
||||
Email: "test_create",
|
||||
AuthModule: "oauth",
|
||||
AuthID: "2032",
|
||||
ID: "",
|
||||
Login: "test_create",
|
||||
Name: "test_create",
|
||||
IsGrafanaAdmin: ptrBool(true),
|
||||
Email: "test_create",
|
||||
AuthenticatedBy: "oauth",
|
||||
AuthID: "2032",
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncUser: true,
|
||||
AllowSignUp: true,
|
||||
@@ -362,13 +362,13 @@ func TestUserSync_SyncUserHook(t *testing.T) {
|
||||
},
|
||||
wantErr: false,
|
||||
wantID: &authn.Identity{
|
||||
ID: "user:2",
|
||||
Login: "test_create",
|
||||
Name: "test_create",
|
||||
Email: "test_create",
|
||||
AuthModule: "oauth",
|
||||
AuthID: "2032",
|
||||
IsGrafanaAdmin: ptrBool(true),
|
||||
ID: "user:2",
|
||||
Login: "test_create",
|
||||
Name: "test_create",
|
||||
Email: "test_create",
|
||||
AuthenticatedBy: "oauth",
|
||||
AuthID: "2032",
|
||||
IsGrafanaAdmin: ptrBool(true),
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncUser: true,
|
||||
AllowSignUp: true,
|
||||
|
||||
Reference in New Issue
Block a user