Files
grafana/pkg/login/auth.go
Jo d4cfbd9fd3 LDAP: Move LDAP globals to Config (#63255)
* structure dtos and private methods

* add basic LDAP service

* use LDAP service in ldap debug API

* lower non fatal error

* remove unused globals

* wip

* remove final globals

* fix tests to use cfg enabled

* restructure errors

* remove logger from globals

* use ldap service in authn

* use ldap service in context handler

* fix failed tests

* fix ldap middleware provides

* fix provides in auth_test.go
2023-02-10 19:01:55 +01:00

115 lines
3.5 KiB
Go

package login
import (
"context"
"errors"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/ldap"
"github.com/grafana/grafana/pkg/services/login"
"github.com/grafana/grafana/pkg/services/loginattempt"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting"
)
var (
ErrEmailNotAllowed = errors.New("required email domain not fulfilled")
ErrInvalidCredentials = errors.New("invalid username or password")
ErrNoEmail = errors.New("login provider didn't return an email address")
ErrProviderDeniedRequest = errors.New("login provider denied login request")
ErrTooManyLoginAttempts = errors.New("too many consecutive incorrect login attempts for user - login for user temporarily blocked")
ErrPasswordEmpty = errors.New("no password provided")
ErrUserDisabled = errors.New("user is disabled")
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")
type Authenticator interface {
AuthenticateUser(context.Context, *login.LoginUserQuery) error
}
type AuthenticatorService struct {
loginService login.Service
loginAttemptService loginattempt.Service
userService user.Service
cfg *setting.Cfg
}
func ProvideService(store db.DB, loginService login.Service,
loginAttemptService loginattempt.Service,
userService user.Service, cfg *setting.Cfg) *AuthenticatorService {
a := &AuthenticatorService{
loginService: loginService,
loginAttemptService: loginAttemptService,
userService: userService,
cfg: cfg,
}
return a
}
// AuthenticateUser authenticates the user via username & password
func (a *AuthenticatorService) AuthenticateUser(ctx context.Context, query *login.LoginUserQuery) error {
ok, err := a.loginAttemptService.Validate(ctx, query.Username)
if err != nil {
return err
}
if !ok {
return ErrTooManyLoginAttempts
}
if err := validatePasswordSet(query.Password); err != nil {
return err
}
isGrafanaLoginEnabled := !query.Cfg.DisableLogin
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
}
ldapEnabled, ldapErr := loginUsingLDAP(ctx, query, a.loginService, a.cfg)
if ldapEnabled {
query.AuthModule = login.LDAPAuthModule
if ldapErr == nil || !errors.Is(ldapErr, ldap.ErrInvalidCredentials) {
return ldapErr
}
if !errors.Is(err, ErrUserDisabled) || !errors.Is(ldapErr, ldap.ErrInvalidCredentials) {
err = ldapErr
}
}
if errors.Is(err, ErrInvalidCredentials) || errors.Is(err, ldap.ErrInvalidCredentials) {
if err := a.loginAttemptService.Add(ctx, query.Username, query.IpAddress); err != nil {
loginLogger.Error("Failed to save invalid login attempt", "err", err)
}
return ErrInvalidCredentials
}
if !isGrafanaLoginEnabled && !ldapEnabled {
return ErrNoAuthProvider
}
return err
}
func validatePasswordSet(password string) error {
if len(password) == 0 {
return ErrPasswordEmpty
}
return nil
}