Auth: Make built-in login configurable (#46978)

This commit is contained in:
Alex
2022-10-12 15:34:59 +00:00
committed by GitHub
parent 7d18460d8f
commit 94ed744454
6 changed files with 46 additions and 4 deletions
+3
View File
@@ -409,6 +409,9 @@ hidden_users =
# Login cookie name
login_cookie_name = grafana_session
# Disable usage of Grafana build-in login solution.
disable_login = false
# The maximum lifetime (duration) an authenticated user can be inactive before being required to login at next visit. Default is 7 days (7d). This setting should be expressed as a duration, e.g. 5m (minutes), 6h (hours), 10d (days), 2w (weeks), 1M (month). The lifetime resets at each successful token rotation (token_rotation_interval_minutes).
login_maximum_inactive_lifetime_duration =
+3
View File
@@ -410,6 +410,9 @@
# Login cookie name
;login_cookie_name = grafana_session
# Disable usage of Grafana build-in login solution.
;disable_login = false
# The maximum lifetime (duration) an authenticated user can be inactive before being required to login at next visit. Default is 7 days (7d). This setting should be expressed as a duration, e.g. 5m (minutes), 6h (hours), 10d (days), 2w (weeks), 1M (month). The lifetime resets at each successful token rotation.
;login_maximum_inactive_lifetime_duration =
+5
View File
@@ -220,6 +220,11 @@ func (hs *HTTPServer) LoginPost(c *models.ReqContext) response.Response {
return resp
}
if errors.Is(err, login.ErrNoAuthProvider) {
resp = response.Error(http.StatusInternalServerError, "No authorization providers enabled", err)
return resp
}
// Do not expose disabled status,
// just show incorrect user credentials error (see #17947)
if errors.Is(err, login.ErrUserDisabled) {
+14 -3
View File
@@ -24,6 +24,7 @@ var (
ErrAbsoluteRedirectTo = errors.New("absolute URLs are not allowed for redirect_to cookie value")
ErrInvalidRedirectTo = errors.New("invalid redirect_to cookie value")
ErrForbiddenRedirectTo = errors.New("forbidden redirect_to cookie value")
ErrNoAuthProvider = errors.New("enable at least one login provider")
)
var loginLogger = log.New("login")
@@ -57,9 +58,15 @@ func (a *AuthenticatorService) AuthenticateUser(ctx context.Context, query *mode
return err
}
err := loginUsingGrafanaDB(ctx, query, a.userService)
if err == nil || (!errors.Is(err, user.ErrUserNotFound) && !errors.Is(err, ErrInvalidCredentials) &&
!errors.Is(err, ErrUserDisabled)) {
isGrafanaLoginEnabled := !query.Cfg.DisableLogin
var err error
if isGrafanaLoginEnabled {
err = loginUsingGrafanaDB(ctx, query, a.userService)
}
if isGrafanaLoginEnabled && (err == nil || (!errors.Is(err, user.ErrUserNotFound) && !errors.Is(err, ErrInvalidCredentials) &&
!errors.Is(err, ErrUserDisabled))) {
query.AuthModule = "grafana"
return err
}
@@ -84,6 +91,10 @@ func (a *AuthenticatorService) AuthenticateUser(ctx context.Context, query *mode
return ErrInvalidCredentials
}
if !isGrafanaLoginEnabled && !ldapEnabled {
return ErrNoAuthProvider
}
return err
}
+18 -1
View File
@@ -11,6 +11,7 @@ import (
"github.com/grafana/grafana/pkg/services/login/logintest"
"github.com/grafana/grafana/pkg/services/loginattempt"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -34,6 +35,21 @@ func TestAuthenticateUser(t *testing.T) {
assert.Empty(t, sc.loginUserQuery.AuthModule)
})
authScenario(t, "When user authenticates with no auth provider enabled", func(sc *authScenarioContext) {
mockLoginAttemptValidation(nil, sc)
sc.loginUserQuery.Cfg.DisableLogin = true
a := AuthenticatorService{loginAttemptService: nil, loginService: &logintest.LoginServiceFake{}}
err := a.AuthenticateUser(context.Background(), sc.loginUserQuery)
require.EqualError(t, err, ErrNoAuthProvider.Error())
assert.True(t, sc.loginAttemptValidationWasCalled)
assert.False(t, sc.grafanaLoginWasCalled)
assert.False(t, sc.ldapLoginWasCalled)
assert.False(t, sc.saveInvalidLoginAttemptWasCalled)
assert.Equal(t, "", sc.loginUserQuery.AuthModule)
})
authScenario(t, "When a user authenticates having too many login attempts", func(sc *authScenarioContext) {
mockLoginAttemptValidation(ErrTooManyLoginAttempts, sc)
mockLoginUsingGrafanaDB(nil, sc)
@@ -218,12 +234,13 @@ func authScenario(t *testing.T, desc string, fn authScenarioFunc) {
origLoginUsingLDAP := loginUsingLDAP
origValidateLoginAttempts := validateLoginAttempts
origSaveInvalidLoginAttempt := saveInvalidLoginAttempt
cfg := setting.Cfg{DisableLogin: false}
sc := &authScenarioContext{
loginUserQuery: &models.LoginUserQuery{
Username: "user",
Password: "pwd",
IpAddress: "192.168.1.1:56433",
Cfg: &cfg,
},
}
+3
View File
@@ -301,6 +301,7 @@ type Cfg struct {
BasicAuthEnabled bool
AdminUser string
AdminPassword string
DisableLogin bool
AdminEmail string
DisableSyncLock bool
@@ -1337,6 +1338,8 @@ func readAuthSettings(iniFile *ini.File, cfg *Cfg) (err error) {
SignoutRedirectUrl = valueAsString(auth, "signout_redirect_url", "")
cfg.OAuthSkipOrgRoleUpdateSync = auth.Key("oauth_skip_org_role_update_sync").MustBool(false)
cfg.DisableLogin = auth.Key("disable_login").MustBool(false)
// SigV4
SigV4AuthEnabled = auth.Key("sigv4_auth_enabled").MustBool(false)
cfg.SigV4AuthEnabled = SigV4AuthEnabled