LDAP: Fix debug view to display the actual computed mapping in ldap.go (#48103)

* LDAP debug fix with Org role inheritance

Co-authored-by: Jguer <joao.guerreiro@grafana.com>

* ldap debug coherent with ldap.go

Co-authored-by: Jguer <joao.guerreiro@grafana.com>

Co-authored-by: Jguer <joao.guerreiro@grafana.com>
pull/48127/head
Gabriel MABILLE 3 years ago committed by GitHub
parent 1566fa2ede
commit 94fd03f44f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 52
      pkg/api/ldap_debug.go
  2. 2
      pkg/services/ldap/helpers.go
  3. 2
      pkg/services/ldap/ldap.go
  4. 2
      pkg/services/ldap/ldap_helpers_test.go

@ -241,7 +241,7 @@ func (hs *HTTPServer) GetUserFromLDAP(c *models.ReqContext) response.Response {
return response.Error(http.StatusBadRequest, "Failed to obtain the LDAP configuration", err) return response.Error(http.StatusBadRequest, "Failed to obtain the LDAP configuration", err)
} }
ldap := newLDAP(ldapConfig.Servers) multiLDAP := newLDAP(ldapConfig.Servers)
username := web.Params(c.Req)[":username"] username := web.Params(c.Req)[":username"]
@ -249,9 +249,8 @@ func (hs *HTTPServer) GetUserFromLDAP(c *models.ReqContext) response.Response {
return response.Error(http.StatusBadRequest, "Validation error. You must specify an username", nil) return response.Error(http.StatusBadRequest, "Validation error. You must specify an username", nil)
} }
user, serverConfig, err := ldap.User(username) user, serverConfig, err := multiLDAP.User(username)
if user == nil || err != nil {
if user == nil {
return response.Error(http.StatusNotFound, "No user was found in the LDAP server(s) with that username", err) return response.Error(http.StatusNotFound, "No user was found in the LDAP server(s) with that username", err)
} }
@ -268,45 +267,32 @@ func (hs *HTTPServer) GetUserFromLDAP(c *models.ReqContext) response.Response {
IsDisabled: user.IsDisabled, IsDisabled: user.IsDisabled,
} }
orgRoles := []LDAPRoleDTO{} unmappedUserGroups := map[string]struct{}{}
// Need to iterate based on the config groups as only the first match for an org is used
// We are showing all matches as that should help in understanding why one match wins out
// over another.
for _, configGroup := range serverConfig.Groups {
for _, userGroup := range user.Groups { for _, userGroup := range user.Groups {
if strings.EqualFold(configGroup.GroupDN, userGroup) { unmappedUserGroups[strings.ToLower(userGroup)] = struct{}{}
r := &LDAPRoleDTO{GroupDN: configGroup.GroupDN, OrgId: configGroup.OrgId, OrgRole: configGroup.OrgRole}
orgRoles = append(orgRoles, *r)
break
}
}
//}
} }
// Then, we find what we did not match by inspecting the list of groups returned from orgRolesMap := map[int64]models.RoleType{}
// LDAP against what we have already matched above. for _, group := range serverConfig.Groups {
for _, userGroup := range user.Groups { // only use the first match for each org
var matched bool if orgRolesMap[group.OrgId] != "" {
continue
for _, orgRole := range orgRoles {
if strings.EqualFold(orgRole.GroupDN, userGroup) { // we already matched it
matched = true
break
}
} }
if !matched { if ldap.IsMemberOf(user.Groups, group.GroupDN) {
r := &LDAPRoleDTO{GroupDN: userGroup} orgRolesMap[group.OrgId] = group.OrgRole
orgRoles = append(orgRoles, *r) u.OrgRoles = append(u.OrgRoles, LDAPRoleDTO{GroupDN: group.GroupDN,
OrgId: group.OrgId, OrgRole: group.OrgRole})
delete(unmappedUserGroups, strings.ToLower(group.GroupDN))
} }
} }
u.OrgRoles = orgRoles for userGroup := range unmappedUserGroups {
u.OrgRoles = append(u.OrgRoles, LDAPRoleDTO{GroupDN: userGroup})
}
ldapLogger.Debug("mapping org roles", "orgsRoles", u.OrgRoles) ldapLogger.Debug("mapping org roles", "orgsRoles", u.OrgRoles)
err = u.FetchOrgs(c.Req.Context(), hs.SQLStore) if err := u.FetchOrgs(c.Req.Context(), hs.SQLStore); err != nil {
if err != nil {
return response.Error(http.StatusBadRequest, "An organization was not found - Please verify your LDAP configuration", err) return response.Error(http.StatusBadRequest, "An organization was not found - Please verify your LDAP configuration", err)
} }

@ -6,7 +6,7 @@ import (
"gopkg.in/ldap.v3" "gopkg.in/ldap.v3"
) )
func isMemberOf(memberOf []string, group string) bool { func IsMemberOf(memberOf []string, group string) bool {
if group == "*" { if group == "*" {
return true return true
} }

@ -422,7 +422,7 @@ func (server *Server) buildGrafanaUser(user *ldap.Entry) (*models.ExternalUserIn
continue continue
} }
if isMemberOf(memberOf, group.GroupDN) { if IsMemberOf(memberOf, group.GroupDN) {
extUser.OrgRoles[group.OrgId] = group.OrgRole extUser.OrgRoles[group.OrgId] = group.OrgRole
if extUser.IsGrafanaAdmin == nil || !*extUser.IsGrafanaAdmin { if extUser.IsGrafanaAdmin == nil || !*extUser.IsGrafanaAdmin {
extUser.IsGrafanaAdmin = group.IsGrafanaAdmin extUser.IsGrafanaAdmin = group.IsGrafanaAdmin

@ -21,7 +21,7 @@ func TestIsMemberOf(t *testing.T) {
for _, tc := range tests { for _, tc := range tests {
t.Run(fmt.Sprintf("isMemberOf(%v, \"%s\") = %v", tc.memberOf, tc.group, tc.expected), func(t *testing.T) { t.Run(fmt.Sprintf("isMemberOf(%v, \"%s\") = %v", tc.memberOf, tc.group, tc.expected), func(t *testing.T) {
assert.Equal(t, tc.expected, isMemberOf(tc.memberOf, tc.group)) assert.Equal(t, tc.expected, IsMemberOf(tc.memberOf, tc.group))
}) })
} }
} }

Loading…
Cancel
Save