LDAP: use authn.IdentitySynchronizer to perform user sync (#73471)

* LDAP: use authn.IdentitySynchronizer to perform sync instaed of login.Service

* use user id as lookup param
This commit is contained in:
Karl Persson 2023-08-18 15:36:44 +02:00 committed by GitHub
parent ffc231147f
commit 1976ac0695
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 52 additions and 40 deletions

View File

@ -14,6 +14,7 @@ import (
"github.com/grafana/grafana/pkg/middleware" "github.com/grafana/grafana/pkg/middleware"
ac "github.com/grafana/grafana/pkg/services/accesscontrol" ac "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/auth" "github.com/grafana/grafana/pkg/services/auth"
"github.com/grafana/grafana/pkg/services/authn"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/ldap" "github.com/grafana/grafana/pkg/services/ldap"
"github.com/grafana/grafana/pkg/services/ldap/multildap" "github.com/grafana/grafana/pkg/services/ldap/multildap"
@ -28,31 +29,33 @@ import (
) )
type Service struct { type Service struct {
cfg *setting.Cfg cfg *setting.Cfg
userService user.Service userService user.Service
authInfoService login.AuthInfoService authInfoService login.AuthInfoService
ldapGroupsService ldap.Groups ldapGroupsService ldap.Groups
loginService login.Service orgService org.Service
orgService org.Service sessionService auth.UserTokenService
sessionService auth.UserTokenService log log.Logger
log log.Logger ldapService service.LDAP
ldapService service.LDAP identitySynchronizer authn.IdentitySynchronizer
} }
func ProvideService(cfg *setting.Cfg, router routing.RouteRegister, accessControl ac.AccessControl, func ProvideService(
cfg *setting.Cfg, router routing.RouteRegister, accessControl ac.AccessControl,
userService user.Service, authInfoService login.AuthInfoService, ldapGroupsService ldap.Groups, userService user.Service, authInfoService login.AuthInfoService, ldapGroupsService ldap.Groups,
loginService login.Service, orgService org.Service, ldapService service.LDAP, identitySynchronizer authn.IdentitySynchronizer, orgService org.Service, ldapService service.LDAP,
sessionService auth.UserTokenService, bundleRegistry supportbundles.Service) *Service { sessionService auth.UserTokenService, bundleRegistry supportbundles.Service,
) *Service {
s := &Service{ s := &Service{
cfg: cfg, cfg: cfg,
userService: userService, userService: userService,
authInfoService: authInfoService, authInfoService: authInfoService,
ldapGroupsService: ldapGroupsService, ldapGroupsService: ldapGroupsService,
loginService: loginService, orgService: orgService,
orgService: orgService, sessionService: sessionService,
sessionService: sessionService, ldapService: ldapService,
ldapService: ldapService, log: log.New("ldap.api"),
log: log.New("ldap.api"), identitySynchronizer: identitySynchronizer,
} }
authorize := ac.Middleware(accessControl) authorize := ac.Middleware(accessControl)
@ -209,14 +212,11 @@ func (s *Service) PostSyncUserWithLDAP(c *contextmodel.ReqContext) response.Resp
return response.Error(http.StatusBadRequest, errMsg, err) return response.Error(http.StatusBadRequest, errMsg, err)
} }
// Since the user was not in the LDAP server. Let's disable it. if err := s.userService.Disable(c.Req.Context(), &user.DisableUserCommand{IsDisabled: true, UserID: usr.ID}); err != nil {
err := s.loginService.DisableExternalUser(c.Req.Context(), usr.Login)
if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to disable the user", err) return response.Error(http.StatusInternalServerError, "Failed to disable the user", err)
} }
err = s.sessionService.RevokeAllUserTokens(c.Req.Context(), userId) if err = s.sessionService.RevokeAllUserTokens(c.Req.Context(), userId); err != nil {
if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to remove session tokens for the user", err) return response.Error(http.StatusInternalServerError, "Failed to remove session tokens for the user", err)
} }
@ -227,19 +227,7 @@ func (s *Service) PostSyncUserWithLDAP(c *contextmodel.ReqContext) response.Resp
return response.Error(http.StatusBadRequest, "Something went wrong while finding the user in LDAP", err) return response.Error(http.StatusBadRequest, "Something went wrong while finding the user in LDAP", err)
} }
upsertCmd := &login.UpsertUserCommand{ if err := s.identitySynchronizer.SyncIdentity(c.Req.Context(), s.identityFromLDAPUser(userInfo)); err != nil {
ReqContext: c,
ExternalUser: userInfo,
SignupAllowed: s.cfg.LDAPAllowSignup,
UserLookupParams: login.UserLookupParams{
UserID: &usr.ID, // Upsert by ID only
Email: nil,
Login: nil,
},
}
_, err = s.loginService.UpsertUser(c.Req.Context(), upsertCmd)
if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to update the user", err) return response.Error(http.StatusInternalServerError, "Failed to update the user", err)
} }
@ -327,6 +315,29 @@ func (s *Service) GetUserFromLDAP(c *contextmodel.ReqContext) response.Response
return response.JSON(http.StatusOK, u) return response.JSON(http.StatusOK, u)
} }
func (s *Service) identityFromLDAPUser(user *login.ExternalUserInfo) *authn.Identity {
return &authn.Identity{
OrgRoles: user.OrgRoles,
Login: user.Login,
Name: user.Name,
Email: user.Email,
IsGrafanaAdmin: user.IsGrafanaAdmin,
AuthenticatedBy: user.AuthModule,
AuthID: user.AuthId,
Groups: user.Groups,
ClientParams: authn.ClientParams{
SyncUser: true,
SyncTeams: true,
EnableDisabledUsers: true,
SyncOrgRoles: !s.cfg.LDAPSkipOrgRoleSync,
AllowSignUp: s.cfg.LDAPAllowSignup,
LookUpParams: login.UserLookupParams{
UserID: &user.UserId,
},
},
}
}
// splitName receives the full name of a user and splits it into two parts: A name and a surname. // splitName receives the full name of a user and splits it into two parts: A name and a surname.
func splitName(name string) (string, string) { func splitName(name string) (string, string) {
names := util.SplitString(name) names := util.SplitString(name)

View File

@ -15,6 +15,7 @@ import (
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl" "github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
"github.com/grafana/grafana/pkg/services/auth/authtest" "github.com/grafana/grafana/pkg/services/auth/authtest"
"github.com/grafana/grafana/pkg/services/authn/authntest"
"github.com/grafana/grafana/pkg/services/ldap" "github.com/grafana/grafana/pkg/services/ldap"
"github.com/grafana/grafana/pkg/services/ldap/multildap" "github.com/grafana/grafana/pkg/services/ldap/multildap"
"github.com/grafana/grafana/pkg/services/ldap/service" "github.com/grafana/grafana/pkg/services/ldap/service"
@ -68,7 +69,7 @@ func setupAPITest(t *testing.T, opts ...func(a *Service)) (*Service, *webtest.Se
usertest.NewUserServiceFake(), usertest.NewUserServiceFake(),
&logintest.AuthInfoServiceFake{}, &logintest.AuthInfoServiceFake{},
ldap.ProvideGroupsService(), ldap.ProvideGroupsService(),
&logintest.LoginServiceFake{}, &authntest.FakeService{},
&orgtest.FakeOrgService{}, &orgtest.FakeOrgService{},
service.NewLDAPFakeService(), service.NewLDAPFakeService(),
authtest.NewFakeUserAuthTokenService(), authtest.NewFakeUserAuthTokenService(),