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:
+37
-35
@@ -200,9 +200,9 @@ type Identity struct {
|
||||
Email string
|
||||
// IsGrafanaAdmin is true if the entity is a Grafana admin.
|
||||
IsGrafanaAdmin *bool
|
||||
// AuthModule is the name of the external system. For example, "auth_ldap" or "auth_saml".
|
||||
// Empty if the identity is provided by Grafana.
|
||||
AuthModule string
|
||||
// AuthenticatedBy is the name of the authentication client that was used to authenticate the current Identity.
|
||||
// For example, "password", "apikey", "auth_ldap" or "auth_azuread".
|
||||
AuthenticatedBy string
|
||||
// AuthId is the unique identifier for the entity in the external system.
|
||||
// Empty if the identity is provided by Grafana.
|
||||
AuthID string
|
||||
@@ -262,21 +262,22 @@ func (i *Identity) SignedInUser() *user.SignedInUser {
|
||||
}
|
||||
|
||||
u := &user.SignedInUser{
|
||||
UserID: 0,
|
||||
OrgID: i.OrgID,
|
||||
OrgName: i.OrgName,
|
||||
OrgRole: i.Role(),
|
||||
Login: i.Login,
|
||||
Name: i.Name,
|
||||
Email: i.Email,
|
||||
OrgCount: i.OrgCount,
|
||||
IsGrafanaAdmin: isGrafanaAdmin,
|
||||
IsAnonymous: i.IsAnonymous,
|
||||
IsDisabled: i.IsDisabled,
|
||||
HelpFlags1: i.HelpFlags1,
|
||||
LastSeenAt: i.LastSeenAt,
|
||||
Teams: i.Teams,
|
||||
Permissions: i.Permissions,
|
||||
UserID: 0,
|
||||
OrgID: i.OrgID,
|
||||
OrgName: i.OrgName,
|
||||
OrgRole: i.Role(),
|
||||
Login: i.Login,
|
||||
Name: i.Name,
|
||||
Email: i.Email,
|
||||
AuthenticatedBy: i.AuthenticatedBy,
|
||||
OrgCount: i.OrgCount,
|
||||
IsGrafanaAdmin: isGrafanaAdmin,
|
||||
IsAnonymous: i.IsAnonymous,
|
||||
IsDisabled: i.IsDisabled,
|
||||
HelpFlags1: i.HelpFlags1,
|
||||
LastSeenAt: i.LastSeenAt,
|
||||
Teams: i.Teams,
|
||||
Permissions: i.Permissions,
|
||||
}
|
||||
|
||||
namespace, id := i.NamespacedID()
|
||||
@@ -294,7 +295,7 @@ func (i *Identity) ExternalUserInfo() login.ExternalUserInfo {
|
||||
_, id := i.NamespacedID()
|
||||
return login.ExternalUserInfo{
|
||||
OAuthToken: i.OAuthToken,
|
||||
AuthModule: i.AuthModule,
|
||||
AuthModule: i.AuthenticatedBy,
|
||||
AuthId: i.AuthID,
|
||||
UserId: id,
|
||||
Email: i.Email,
|
||||
@@ -308,23 +309,24 @@ func (i *Identity) ExternalUserInfo() login.ExternalUserInfo {
|
||||
}
|
||||
|
||||
// IdentityFromSignedInUser creates an identity from a SignedInUser.
|
||||
func IdentityFromSignedInUser(id string, usr *user.SignedInUser, params ClientParams) *Identity {
|
||||
func IdentityFromSignedInUser(id string, usr *user.SignedInUser, params ClientParams, authenticatedBy string) *Identity {
|
||||
return &Identity{
|
||||
ID: id,
|
||||
OrgID: usr.OrgID,
|
||||
OrgName: usr.OrgName,
|
||||
OrgRoles: map[int64]org.RoleType{usr.OrgID: usr.OrgRole},
|
||||
Login: usr.Login,
|
||||
Name: usr.Name,
|
||||
Email: usr.Email,
|
||||
OrgCount: usr.OrgCount,
|
||||
IsGrafanaAdmin: &usr.IsGrafanaAdmin,
|
||||
IsDisabled: usr.IsDisabled,
|
||||
HelpFlags1: usr.HelpFlags1,
|
||||
LastSeenAt: usr.LastSeenAt,
|
||||
Teams: usr.Teams,
|
||||
ClientParams: params,
|
||||
Permissions: usr.Permissions,
|
||||
ID: id,
|
||||
OrgID: usr.OrgID,
|
||||
OrgName: usr.OrgName,
|
||||
OrgRoles: map[int64]org.RoleType{usr.OrgID: usr.OrgRole},
|
||||
Login: usr.Login,
|
||||
Name: usr.Name,
|
||||
Email: usr.Email,
|
||||
AuthenticatedBy: authenticatedBy,
|
||||
OrgCount: usr.OrgCount,
|
||||
IsGrafanaAdmin: &usr.IsGrafanaAdmin,
|
||||
IsDisabled: usr.IsDisabled,
|
||||
HelpFlags1: usr.HelpFlags1,
|
||||
LastSeenAt: usr.LastSeenAt,
|
||||
Teams: usr.Teams,
|
||||
ClientParams: params,
|
||||
Permissions: usr.Permissions,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/apikey"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
@@ -64,10 +65,11 @@ func (s *APIKey) Authenticate(ctx context.Context, r *authn.Request) (*authn.Ide
|
||||
// if the api key don't belong to a service account construct the identity and return it
|
||||
if apiKey.ServiceAccountId == nil || *apiKey.ServiceAccountId < 1 {
|
||||
return &authn.Identity{
|
||||
ID: authn.NamespacedID(authn.NamespaceAPIKey, apiKey.ID),
|
||||
OrgID: apiKey.OrgID,
|
||||
OrgRoles: map[int64]org.RoleType{apiKey.OrgID: apiKey.Role},
|
||||
ClientParams: authn.ClientParams{SyncPermissions: true},
|
||||
ID: authn.NamespacedID(authn.NamespaceAPIKey, apiKey.ID),
|
||||
OrgID: apiKey.OrgID,
|
||||
OrgRoles: map[int64]org.RoleType{apiKey.OrgID: apiKey.Role},
|
||||
ClientParams: authn.ClientParams{SyncPermissions: true},
|
||||
AuthenticatedBy: login.APIKeyAuthModule,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -80,7 +82,7 @@ func (s *APIKey) Authenticate(ctx context.Context, r *authn.Request) (*authn.Ide
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return authn.IdentityFromSignedInUser(authn.NamespacedID(authn.NamespaceServiceAccount, usr.UserID), usr, authn.ClientParams{SyncPermissions: true}), nil
|
||||
return authn.IdentityFromSignedInUser(authn.NamespacedID(authn.NamespaceServiceAccount, usr.UserID), usr, authn.ClientParams{SyncPermissions: true}, login.APIKeyAuthModule), nil
|
||||
}
|
||||
|
||||
func (s *APIKey) getAPIKey(ctx context.Context, token string) (*apikey.APIKey, error) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/apikey"
|
||||
"github.com/grafana/grafana/pkg/services/apikey/apikeytest"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/services/user/usertest"
|
||||
@@ -55,6 +56,7 @@ func TestAPIKey_Authenticate(t *testing.T) {
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncPermissions: true,
|
||||
},
|
||||
AuthenticatedBy: login.APIKeyAuthModule,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -88,6 +90,7 @@ func TestAPIKey_Authenticate(t *testing.T) {
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncPermissions: true,
|
||||
},
|
||||
AuthenticatedBy: login.APIKeyAuthModule,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
"github.com/grafana/grafana/pkg/services/oauthserver"
|
||||
"github.com/grafana/grafana/pkg/services/signingkeys"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
@@ -100,7 +101,7 @@ func (s *ExtendedJWT) Authenticate(ctx context.Context, r *authn.Request) (*auth
|
||||
|
||||
signedInUser.Permissions[s.getDefaultOrgID()] = claims.Entitlements
|
||||
|
||||
return authn.IdentityFromSignedInUser(authn.NamespacedID(authn.NamespaceUser, signedInUser.UserID), signedInUser, authn.ClientParams{SyncPermissions: false}), nil
|
||||
return authn.IdentityFromSignedInUser(authn.NamespacedID(authn.NamespaceUser, signedInUser.UserID), signedInUser, authn.ClientParams{SyncPermissions: false}, login.ExtendedJWTModule), nil
|
||||
}
|
||||
|
||||
func (s *ExtendedJWT) Test(ctx context.Context, r *authn.Request) bool {
|
||||
|
||||
@@ -150,19 +150,19 @@ func TestExtendedJWT_Authenticate(t *testing.T) {
|
||||
}
|
||||
},
|
||||
want: &authn.Identity{
|
||||
OrgID: 1,
|
||||
OrgCount: 0,
|
||||
OrgName: "",
|
||||
OrgRoles: map[int64]roletype.RoleType{1: roletype.RoleAdmin},
|
||||
ID: "user:2",
|
||||
Login: "johndoe",
|
||||
Name: "John Doe",
|
||||
Email: "johndoe@grafana.com",
|
||||
IsGrafanaAdmin: boolPtr(false),
|
||||
AuthModule: "",
|
||||
AuthID: "",
|
||||
IsDisabled: false,
|
||||
HelpFlags1: 0,
|
||||
OrgID: 1,
|
||||
OrgCount: 0,
|
||||
OrgName: "",
|
||||
OrgRoles: map[int64]roletype.RoleType{1: roletype.RoleAdmin},
|
||||
ID: "user:2",
|
||||
Login: "johndoe",
|
||||
Name: "John Doe",
|
||||
Email: "johndoe@grafana.com",
|
||||
IsGrafanaAdmin: boolPtr(false),
|
||||
AuthenticatedBy: login.ExtendedJWTModule,
|
||||
AuthID: "",
|
||||
IsDisabled: false,
|
||||
HelpFlags1: 0,
|
||||
Permissions: map[int64]map[string][]string{
|
||||
1: {
|
||||
"dashboards:create": {
|
||||
|
||||
@@ -32,8 +32,8 @@ func (c *Grafana) String() string {
|
||||
|
||||
func (c *Grafana) AuthenticateProxy(ctx context.Context, r *authn.Request, username string, additional map[string]string) (*authn.Identity, error) {
|
||||
identity := &authn.Identity{
|
||||
AuthModule: login.AuthProxyAuthModule,
|
||||
AuthID: username,
|
||||
AuthenticatedBy: login.AuthProxyAuthModule,
|
||||
AuthID: username,
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncUser: true,
|
||||
SyncTeams: true,
|
||||
@@ -109,7 +109,7 @@ func (c *Grafana) AuthenticatePassword(ctx context.Context, r *authn.Request, us
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return authn.IdentityFromSignedInUser(authn.NamespacedID(authn.NamespaceUser, signedInUser.UserID), signedInUser, authn.ClientParams{SyncPermissions: true}), nil
|
||||
return authn.IdentityFromSignedInUser(authn.NamespacedID(authn.NamespaceUser, signedInUser.UserID), signedInUser, authn.ClientParams{SyncPermissions: true}, login.PasswordAuthModule), nil
|
||||
}
|
||||
|
||||
func comparePassword(password, salt, hash string) bool {
|
||||
|
||||
@@ -40,13 +40,13 @@ func TestGrafana_AuthenticateProxy(t *testing.T) {
|
||||
proxyFieldEmail: "email@email.com",
|
||||
},
|
||||
expectedIdentity: &authn.Identity{
|
||||
OrgRoles: map[int64]org.RoleType{1: org.RoleViewer},
|
||||
Login: "test",
|
||||
Name: "name",
|
||||
Email: "email@email.com",
|
||||
AuthModule: "authproxy",
|
||||
AuthID: "test",
|
||||
Groups: []string{"grp1", "grp2"},
|
||||
OrgRoles: map[int64]org.RoleType{1: org.RoleViewer},
|
||||
Login: "test",
|
||||
Name: "name",
|
||||
Email: "email@email.com",
|
||||
AuthenticatedBy: login.AuthProxyAuthModule,
|
||||
AuthID: "test",
|
||||
Groups: []string{"grp1", "grp2"},
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncUser: true,
|
||||
SyncTeams: true,
|
||||
@@ -66,10 +66,10 @@ func TestGrafana_AuthenticateProxy(t *testing.T) {
|
||||
req: &authn.Request{HTTPRequest: &http.Request{Header: map[string][]string{}}},
|
||||
additional: map[string]string{},
|
||||
expectedIdentity: &authn.Identity{
|
||||
Login: "test@test.com",
|
||||
Email: "test@test.com",
|
||||
AuthModule: "authproxy",
|
||||
AuthID: "test@test.com",
|
||||
Login: "test@test.com",
|
||||
Email: "test@test.com",
|
||||
AuthenticatedBy: login.AuthProxyAuthModule,
|
||||
AuthID: "test@test.com",
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncUser: true,
|
||||
SyncTeams: true,
|
||||
@@ -106,7 +106,7 @@ func TestGrafana_AuthenticateProxy(t *testing.T) {
|
||||
assert.Equal(t, tt.expectedIdentity.Name, identity.Name)
|
||||
assert.Equal(t, tt.expectedIdentity.Email, identity.Email)
|
||||
assert.Equal(t, tt.expectedIdentity.AuthID, identity.AuthID)
|
||||
assert.Equal(t, tt.expectedIdentity.AuthModule, identity.AuthModule)
|
||||
assert.Equal(t, tt.expectedIdentity.AuthenticatedBy, identity.AuthenticatedBy)
|
||||
assert.Equal(t, tt.expectedIdentity.Groups, identity.Groups)
|
||||
|
||||
assert.Equal(t, tt.expectedIdentity.ClientParams.SyncUser, identity.ClientParams.SyncUser)
|
||||
@@ -143,11 +143,13 @@ func TestGrafana_AuthenticatePassword(t *testing.T) {
|
||||
findUser: true,
|
||||
expectedSignedInUser: &user.SignedInUser{UserID: 1, OrgID: 1, OrgRole: "Viewer"},
|
||||
expectedIdentity: &authn.Identity{
|
||||
ID: "user:1",
|
||||
OrgID: 1,
|
||||
OrgRoles: map[int64]org.RoleType{1: "Viewer"},
|
||||
IsGrafanaAdmin: boolPtr(false),
|
||||
ClientParams: authn.ClientParams{SyncPermissions: true}},
|
||||
ID: "user:1",
|
||||
OrgID: 1,
|
||||
OrgRoles: map[int64]org.RoleType{1: "Viewer"},
|
||||
IsGrafanaAdmin: boolPtr(false),
|
||||
ClientParams: authn.ClientParams{SyncPermissions: true},
|
||||
AuthenticatedBy: login.PasswordAuthModule,
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should fail for incorrect password",
|
||||
|
||||
@@ -66,9 +66,9 @@ func (s *JWT) Authenticate(ctx context.Context, r *authn.Request) (*authn.Identi
|
||||
}
|
||||
|
||||
id := &authn.Identity{
|
||||
AuthModule: login.JWTModule,
|
||||
AuthID: sub,
|
||||
OrgRoles: map[int64]org.RoleType{},
|
||||
AuthenticatedBy: login.JWTModule,
|
||||
AuthID: sub,
|
||||
OrgRoles: map[int64]org.RoleType{},
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncUser: true,
|
||||
FetchSyncedUser: true,
|
||||
|
||||
@@ -35,19 +35,19 @@ func TestAuthenticateJWT(t *testing.T) {
|
||||
}
|
||||
jwtHeaderName := "X-Forwarded-User"
|
||||
wantID := &authn.Identity{
|
||||
OrgID: 0,
|
||||
OrgCount: 0,
|
||||
OrgName: "",
|
||||
OrgRoles: map[int64]roletype.RoleType{1: roletype.RoleAdmin},
|
||||
ID: "",
|
||||
Login: "eai-doe",
|
||||
Name: "Eai Doe",
|
||||
Email: "eai.doe@cor.po",
|
||||
IsGrafanaAdmin: boolPtr(false),
|
||||
AuthModule: "jwt",
|
||||
AuthID: "1234567890",
|
||||
IsDisabled: false,
|
||||
HelpFlags1: 0,
|
||||
OrgID: 0,
|
||||
OrgCount: 0,
|
||||
OrgName: "",
|
||||
OrgRoles: map[int64]roletype.RoleType{1: roletype.RoleAdmin},
|
||||
ID: "",
|
||||
Login: "eai-doe",
|
||||
Name: "Eai Doe",
|
||||
Email: "eai.doe@cor.po",
|
||||
IsGrafanaAdmin: boolPtr(false),
|
||||
AuthenticatedBy: login.JWTModule,
|
||||
AuthID: "1234567890",
|
||||
IsDisabled: false,
|
||||
HelpFlags1: 0,
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncUser: true,
|
||||
AllowSignUp: true,
|
||||
|
||||
@@ -71,15 +71,15 @@ func (c *LDAP) AuthenticatePassword(ctx context.Context, r *authn.Request, usern
|
||||
|
||||
func (c *LDAP) identityFromLDAPInfo(orgID int64, info *login.ExternalUserInfo) *authn.Identity {
|
||||
return &authn.Identity{
|
||||
OrgID: orgID,
|
||||
OrgRoles: info.OrgRoles,
|
||||
Login: info.Login,
|
||||
Name: info.Name,
|
||||
Email: info.Email,
|
||||
IsGrafanaAdmin: info.IsGrafanaAdmin,
|
||||
AuthModule: info.AuthModule,
|
||||
AuthID: info.AuthId,
|
||||
Groups: info.Groups,
|
||||
OrgID: orgID,
|
||||
OrgRoles: info.OrgRoles,
|
||||
Login: info.Login,
|
||||
Name: info.Name,
|
||||
Email: info.Email,
|
||||
IsGrafanaAdmin: info.IsGrafanaAdmin,
|
||||
AuthenticatedBy: info.AuthModule,
|
||||
AuthID: info.AuthId,
|
||||
Groups: info.Groups,
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncUser: true,
|
||||
SyncTeams: true,
|
||||
|
||||
@@ -39,14 +39,14 @@ func TestLDAP_AuthenticateProxy(t *testing.T) {
|
||||
OrgRoles: map[int64]org.RoleType{1: org.RoleViewer},
|
||||
},
|
||||
expectedIdentity: &authn.Identity{
|
||||
OrgID: 1,
|
||||
OrgRoles: map[int64]org.RoleType{1: org.RoleViewer},
|
||||
Login: "test",
|
||||
Name: "test test",
|
||||
Email: "test@test.com",
|
||||
AuthModule: login.LDAPAuthModule,
|
||||
AuthID: "123",
|
||||
Groups: []string{"1", "2"},
|
||||
OrgID: 1,
|
||||
OrgRoles: map[int64]org.RoleType{1: org.RoleViewer},
|
||||
Login: "test",
|
||||
Name: "test test",
|
||||
Email: "test@test.com",
|
||||
AuthenticatedBy: login.LDAPAuthModule,
|
||||
AuthID: "123",
|
||||
Groups: []string{"1", "2"},
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncUser: true,
|
||||
SyncTeams: true,
|
||||
@@ -105,14 +105,14 @@ func TestLDAP_AuthenticatePassword(t *testing.T) {
|
||||
OrgRoles: map[int64]org.RoleType{1: org.RoleViewer},
|
||||
},
|
||||
expectedIdentity: &authn.Identity{
|
||||
OrgID: 1,
|
||||
OrgRoles: map[int64]org.RoleType{1: org.RoleViewer},
|
||||
Login: "test",
|
||||
Name: "test test",
|
||||
Email: "test@test.com",
|
||||
AuthModule: login.LDAPAuthModule,
|
||||
AuthID: "123",
|
||||
Groups: []string{"1", "2"},
|
||||
OrgID: 1,
|
||||
OrgRoles: map[int64]org.RoleType{1: org.RoleViewer},
|
||||
Login: "test",
|
||||
Name: "test test",
|
||||
Email: "test@test.com",
|
||||
AuthenticatedBy: login.LDAPAuthModule,
|
||||
AuthID: "123",
|
||||
Groups: []string{"1", "2"},
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncUser: true,
|
||||
SyncTeams: true,
|
||||
|
||||
@@ -146,15 +146,15 @@ func (c *OAuth) Authenticate(ctx context.Context, r *authn.Request) (*authn.Iden
|
||||
}
|
||||
|
||||
return &authn.Identity{
|
||||
Login: userInfo.Login,
|
||||
Name: userInfo.Name,
|
||||
Email: userInfo.Email,
|
||||
IsGrafanaAdmin: isGrafanaAdmin,
|
||||
AuthModule: c.moduleName,
|
||||
AuthID: userInfo.Id,
|
||||
Groups: userInfo.Groups,
|
||||
OAuthToken: token,
|
||||
OrgRoles: orgRoles,
|
||||
Login: userInfo.Login,
|
||||
Name: userInfo.Name,
|
||||
Email: userInfo.Email,
|
||||
IsGrafanaAdmin: isGrafanaAdmin,
|
||||
AuthenticatedBy: c.moduleName,
|
||||
AuthID: userInfo.Id,
|
||||
Groups: userInfo.Groups,
|
||||
OAuthToken: token,
|
||||
OrgRoles: orgRoles,
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncUser: true,
|
||||
SyncTeams: true,
|
||||
|
||||
@@ -129,13 +129,13 @@ func TestOAuth_Authenticate(t *testing.T) {
|
||||
Groups: []string{"grp1", "grp2"},
|
||||
},
|
||||
expectedIdentity: &authn.Identity{
|
||||
Email: "some@email.com",
|
||||
AuthModule: "oauth_azuread",
|
||||
AuthID: "123",
|
||||
Name: "name",
|
||||
Groups: []string{"grp1", "grp2"},
|
||||
OAuthToken: &oauth2.Token{},
|
||||
OrgRoles: map[int64]org.RoleType{1: org.RoleAdmin},
|
||||
Email: "some@email.com",
|
||||
AuthenticatedBy: login.AzureADAuthModule,
|
||||
AuthID: "123",
|
||||
Name: "name",
|
||||
Groups: []string{"grp1", "grp2"},
|
||||
OAuthToken: &oauth2.Token{},
|
||||
OrgRoles: map[int64]org.RoleType{1: org.RoleAdmin},
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncUser: true,
|
||||
SyncTeams: true,
|
||||
@@ -168,13 +168,13 @@ func TestOAuth_Authenticate(t *testing.T) {
|
||||
Groups: []string{"grp1", "grp2"},
|
||||
},
|
||||
expectedIdentity: &authn.Identity{
|
||||
Email: "some@email.com",
|
||||
AuthModule: "oauth_azuread",
|
||||
AuthID: "123",
|
||||
Name: "name",
|
||||
Groups: []string{"grp1", "grp2"},
|
||||
OAuthToken: &oauth2.Token{},
|
||||
OrgRoles: map[int64]org.RoleType{1: org.RoleAdmin},
|
||||
Email: "some@email.com",
|
||||
AuthenticatedBy: login.AzureADAuthModule,
|
||||
AuthID: "123",
|
||||
Name: "name",
|
||||
Groups: []string{"grp1", "grp2"},
|
||||
OAuthToken: &oauth2.Token{},
|
||||
OrgRoles: map[int64]org.RoleType{1: org.RoleAdmin},
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncUser: true,
|
||||
SyncTeams: true,
|
||||
@@ -221,7 +221,7 @@ func TestOAuth_Authenticate(t *testing.T) {
|
||||
assert.Equal(t, tt.expectedIdentity.Name, identity.Name)
|
||||
assert.Equal(t, tt.expectedIdentity.Email, identity.Email)
|
||||
assert.Equal(t, tt.expectedIdentity.AuthID, identity.AuthID)
|
||||
assert.Equal(t, tt.expectedIdentity.AuthModule, identity.AuthModule)
|
||||
assert.Equal(t, tt.expectedIdentity.AuthenticatedBy, identity.AuthenticatedBy)
|
||||
assert.Equal(t, tt.expectedIdentity.Groups, identity.Groups)
|
||||
|
||||
assert.Equal(t, tt.expectedIdentity.ClientParams.SyncUser, identity.ClientParams.SyncUser)
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
@@ -99,7 +100,7 @@ func (c *Proxy) Authenticate(ctx context.Context, r *authn.Request) (*authn.Iden
|
||||
// and perform syncs
|
||||
if usr != nil {
|
||||
c.log.FromContext(ctx).Debug("User was loaded from cache, skip syncs", "userId", usr.UserID)
|
||||
return authn.IdentityFromSignedInUser(authn.NamespacedID(authn.NamespaceUser, usr.UserID), usr, authn.ClientParams{SyncPermissions: true}), nil
|
||||
return authn.IdentityFromSignedInUser(authn.NamespacedID(authn.NamespaceUser, usr.UserID), usr, authn.ClientParams{SyncPermissions: true}, login.AuthProxyAuthModule), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,11 +56,11 @@ func (c *Render) Authenticate(ctx context.Context, r *authn.Request) (*authn.Ide
|
||||
return nil, err
|
||||
}
|
||||
|
||||
identity = authn.IdentityFromSignedInUser(authn.NamespacedID(authn.NamespaceUser, usr.UserID), usr, authn.ClientParams{SyncPermissions: true})
|
||||
identity = authn.IdentityFromSignedInUser(authn.NamespacedID(authn.NamespaceUser, usr.UserID), usr, authn.ClientParams{SyncPermissions: true}, login.RenderModule)
|
||||
}
|
||||
|
||||
identity.LastSeenAt = time.Now()
|
||||
identity.AuthModule = login.RenderModule
|
||||
identity.AuthenticatedBy = login.RenderModule
|
||||
return identity, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -38,11 +38,11 @@ func TestRender_Authenticate(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expectedIdentity: &authn.Identity{
|
||||
ID: "user:0",
|
||||
OrgID: 1,
|
||||
OrgRoles: map[int64]org.RoleType{1: org.RoleViewer},
|
||||
AuthModule: login.RenderModule,
|
||||
ClientParams: authn.ClientParams{SyncPermissions: true},
|
||||
ID: "user:0",
|
||||
OrgID: 1,
|
||||
OrgRoles: map[int64]org.RoleType{1: org.RoleViewer},
|
||||
AuthenticatedBy: login.RenderModule,
|
||||
ClientParams: authn.ClientParams{SyncPermissions: true},
|
||||
},
|
||||
expectedRenderUsr: &rendering.RenderUser{
|
||||
OrgID: 1,
|
||||
@@ -59,13 +59,13 @@ func TestRender_Authenticate(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expectedIdentity: &authn.Identity{
|
||||
ID: "user:1",
|
||||
OrgID: 1,
|
||||
OrgName: "test",
|
||||
OrgRoles: map[int64]org.RoleType{1: org.RoleAdmin},
|
||||
IsGrafanaAdmin: boolPtr(false),
|
||||
AuthModule: login.RenderModule,
|
||||
ClientParams: authn.ClientParams{SyncPermissions: true},
|
||||
ID: "user:1",
|
||||
OrgID: 1,
|
||||
OrgName: "test",
|
||||
OrgRoles: map[int64]org.RoleType{1: org.RoleAdmin},
|
||||
IsGrafanaAdmin: boolPtr(false),
|
||||
AuthenticatedBy: login.RenderModule,
|
||||
ClientParams: authn.ClientParams{SyncPermissions: true},
|
||||
},
|
||||
expectedRenderUsr: &rendering.RenderUser{
|
||||
OrgID: 1,
|
||||
|
||||
Reference in New Issue
Block a user