2019-09-03 12:34:44 -05:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
2022-04-14 10:54:49 -05:00
|
|
|
"encoding/json"
|
2019-09-04 09:29:14 -05:00
|
|
|
"errors"
|
2023-02-08 02:32:59 -06:00
|
|
|
"io"
|
2019-09-03 12:34:44 -05:00
|
|
|
"net/http"
|
2023-02-08 02:32:59 -06:00
|
|
|
"os"
|
2019-09-03 12:34:44 -05:00
|
|
|
"testing"
|
|
|
|
|
2022-08-02 09:58:05 -05:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
2021-06-11 08:58:18 -05:00
|
|
|
|
2021-01-15 07:43:20 -06:00
|
|
|
"github.com/grafana/grafana/pkg/api/routing"
|
2022-08-02 09:58:05 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
2023-02-08 02:32:59 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
|
2022-11-18 02:56:06 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/auth/authtest"
|
2019-09-03 12:34:44 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/ldap"
|
2023-02-08 02:32:59 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/ldap/multildap"
|
2023-02-10 12:01:55 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/ldap/service"
|
2023-01-27 12:36:54 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/login"
|
2022-08-02 09:58:05 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/login/logintest"
|
2022-08-10 04:56:48 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/org"
|
2022-09-20 02:55:40 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/org/orgtest"
|
2023-02-09 09:31:31 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest"
|
2022-08-02 09:58:05 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/user"
|
|
|
|
"github.com/grafana/grafana/pkg/services/user/usertest"
|
2019-09-03 12:34:44 -05:00
|
|
|
"github.com/grafana/grafana/pkg/setting"
|
2023-01-19 04:09:26 -06:00
|
|
|
"github.com/grafana/grafana/pkg/web/webtest"
|
2019-09-03 12:34:44 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
type LDAPMock struct {
|
2023-02-08 02:32:59 -06:00
|
|
|
Results []*login.ExternalUserInfo
|
|
|
|
UserSearchResult *login.ExternalUserInfo
|
|
|
|
UserSearchConfig ldap.ServerConfig
|
|
|
|
UserSearchError error
|
2019-09-03 12:34:44 -05:00
|
|
|
}
|
|
|
|
|
2019-09-04 09:29:14 -05:00
|
|
|
var pingResult []*multildap.ServerStatus
|
|
|
|
var pingError error
|
|
|
|
|
|
|
|
func (m *LDAPMock) Ping() ([]*multildap.ServerStatus, error) {
|
|
|
|
return pingResult, pingError
|
|
|
|
}
|
2019-09-03 12:34:44 -05:00
|
|
|
|
2023-01-27 12:36:54 -06:00
|
|
|
func (m *LDAPMock) Login(query *login.LoginUserQuery) (*login.ExternalUserInfo, error) {
|
|
|
|
return &login.ExternalUserInfo{}, nil
|
2019-09-03 12:34:44 -05:00
|
|
|
}
|
|
|
|
|
2023-01-27 12:36:54 -06:00
|
|
|
func (m *LDAPMock) Users(logins []string) ([]*login.ExternalUserInfo, error) {
|
|
|
|
s := []*login.ExternalUserInfo{}
|
2019-09-03 12:34:44 -05:00
|
|
|
return s, nil
|
|
|
|
}
|
|
|
|
|
2023-01-27 12:36:54 -06:00
|
|
|
func (m *LDAPMock) User(login string) (*login.ExternalUserInfo, ldap.ServerConfig, error) {
|
2023-02-08 02:32:59 -06:00
|
|
|
return m.UserSearchResult, m.UserSearchConfig, m.UserSearchError
|
2019-09-13 10:26:25 -05:00
|
|
|
}
|
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
func setupAPITest(t *testing.T, opts ...func(a *Service)) (*Service, *webtest.Server) {
|
2019-09-03 12:34:44 -05:00
|
|
|
t.Helper()
|
2023-02-08 02:32:59 -06:00
|
|
|
router := routing.NewRouteRegister()
|
|
|
|
cfg := setting.NewCfg()
|
2023-02-09 09:31:31 -06:00
|
|
|
cfg.LDAPEnabled = true
|
2023-02-08 02:32:59 -06:00
|
|
|
|
|
|
|
a := ProvideService(cfg,
|
|
|
|
router,
|
|
|
|
acimpl.ProvideAccessControl(cfg),
|
|
|
|
usertest.NewUserServiceFake(),
|
|
|
|
&logintest.AuthInfoServiceFake{},
|
|
|
|
ldap.ProvideGroupsService(),
|
|
|
|
&logintest.LoginServiceFake{},
|
|
|
|
&orgtest.FakeOrgService{},
|
2023-02-10 12:01:55 -06:00
|
|
|
service.NewLDAPFakeService(),
|
2023-02-08 02:32:59 -06:00
|
|
|
authtest.NewFakeUserAuthTokenService(),
|
2023-02-09 09:31:31 -06:00
|
|
|
supportbundlestest.NewFakeBundleService(),
|
2023-02-08 02:32:59 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
for _, o := range opts {
|
|
|
|
o(a)
|
|
|
|
}
|
2019-09-03 12:34:44 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
server := webtest.NewServer(t, router)
|
2019-09-03 12:34:44 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
return a, server
|
2019-09-03 12:34:44 -05:00
|
|
|
}
|
|
|
|
|
2020-11-13 02:52:38 -06:00
|
|
|
func TestGetUserFromLDAPAPIEndpoint_UserNotFound(t *testing.T) {
|
2023-02-08 02:32:59 -06:00
|
|
|
_, server := setupAPITest(t, func(a *Service) {
|
|
|
|
a.orgService = &orgtest.FakeOrgService{
|
|
|
|
ExpectedOrgs: []*org.OrgDTO{},
|
|
|
|
}
|
2023-02-10 12:01:55 -06:00
|
|
|
a.ldapService = &service.LDAPFakeService{
|
|
|
|
ExpectedClient: &LDAPMock{
|
|
|
|
UserSearchResult: nil,
|
|
|
|
},
|
|
|
|
ExpectedConfig: &ldap.Config{},
|
|
|
|
}
|
2023-02-08 02:32:59 -06:00
|
|
|
})
|
2019-09-03 12:34:44 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
req := server.NewGetRequest("/api/admin/ldap/user-that-does-not-exist")
|
|
|
|
webtest.RequestWithSignedInUser(req, &user.SignedInUser{
|
|
|
|
OrgID: 1,
|
|
|
|
Permissions: map[int64]map[string][]string{
|
|
|
|
1: {"ldap.user:read": {"*"}}},
|
|
|
|
})
|
2019-09-03 12:34:44 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
res, err := server.Send(req)
|
|
|
|
defer func() { require.NoError(t, res.Body.Close()) }()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
assert.Equal(t, http.StatusNotFound, res.StatusCode)
|
|
|
|
bodyBytes, _ := io.ReadAll(res.Body)
|
|
|
|
assert.JSONEq(t, "{\"message\":\"No user was found in the LDAP server(s) with that username\"}", string(bodyBytes))
|
2019-09-03 12:34:44 -05:00
|
|
|
}
|
|
|
|
|
2020-11-13 02:52:38 -06:00
|
|
|
func TestGetUserFromLDAPAPIEndpoint_OrgNotfound(t *testing.T) {
|
2019-09-03 12:34:44 -05:00
|
|
|
isAdmin := true
|
2023-02-08 02:32:59 -06:00
|
|
|
userSearchResult := &login.ExternalUserInfo{
|
2019-09-03 12:34:44 -05:00
|
|
|
Name: "John Doe",
|
|
|
|
Email: "john.doe@example.com",
|
|
|
|
Login: "johndoe",
|
2019-09-19 10:13:38 -05:00
|
|
|
Groups: []string{"cn=admins,ou=groups,dc=grafana,dc=org"},
|
2022-08-10 04:56:48 -05:00
|
|
|
OrgRoles: map[int64]org.RoleType{1: org.RoleAdmin, 2: org.RoleViewer},
|
2019-09-03 12:34:44 -05:00
|
|
|
IsGrafanaAdmin: &isAdmin,
|
|
|
|
}
|
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
userSearchConfig := ldap.ServerConfig{
|
2019-09-03 12:34:44 -05:00
|
|
|
Attr: ldap.AttributeMap{
|
|
|
|
Name: "ldap-name",
|
|
|
|
Surname: "ldap-surname",
|
|
|
|
Email: "ldap-email",
|
|
|
|
Username: "ldap-username",
|
|
|
|
},
|
|
|
|
Groups: []*ldap.GroupToOrgRole{
|
|
|
|
{
|
|
|
|
GroupDN: "cn=admins,ou=groups,dc=grafana,dc=org",
|
2019-09-19 10:13:38 -05:00
|
|
|
OrgId: 1,
|
2022-08-10 04:56:48 -05:00
|
|
|
OrgRole: org.RoleAdmin,
|
2019-09-03 12:34:44 -05:00
|
|
|
},
|
|
|
|
{
|
2019-11-01 09:42:22 -05:00
|
|
|
GroupDN: "cn=admins,ou=groups,dc=grafana,dc=org",
|
2019-09-19 10:13:38 -05:00
|
|
|
OrgId: 2,
|
2022-08-10 04:56:48 -05:00
|
|
|
OrgRole: org.RoleViewer,
|
2019-09-03 12:34:44 -05:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2022-09-20 02:55:40 -05:00
|
|
|
mockOrgSearchResult := []*org.OrgDTO{
|
|
|
|
{ID: 1, Name: "Main Org."},
|
2019-09-03 12:34:44 -05:00
|
|
|
}
|
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
_, server := setupAPITest(t, func(a *Service) {
|
|
|
|
a.orgService = &orgtest.FakeOrgService{
|
|
|
|
ExpectedOrgs: mockOrgSearchResult,
|
|
|
|
}
|
2023-02-10 12:01:55 -06:00
|
|
|
a.ldapService = &service.LDAPFakeService{
|
|
|
|
ExpectedClient: &LDAPMock{
|
|
|
|
UserSearchResult: userSearchResult,
|
|
|
|
UserSearchConfig: userSearchConfig,
|
|
|
|
},
|
|
|
|
ExpectedConfig: &ldap.Config{},
|
|
|
|
}
|
2023-02-08 02:32:59 -06:00
|
|
|
})
|
|
|
|
|
|
|
|
req := server.NewGetRequest("/api/admin/ldap/johndoe")
|
|
|
|
webtest.RequestWithSignedInUser(req, &user.SignedInUser{
|
|
|
|
OrgID: 1,
|
|
|
|
Permissions: map[int64]map[string][]string{
|
|
|
|
1: {"ldap.user:read": {"*"}}},
|
|
|
|
})
|
2019-09-03 12:34:44 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
res, err := server.Send(req)
|
|
|
|
defer func() { require.NoError(t, res.Body.Close()) }()
|
|
|
|
require.NoError(t, err)
|
2019-09-03 12:34:44 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
assert.Equal(t, http.StatusBadRequest, res.StatusCode)
|
|
|
|
bodyBytes, _ := io.ReadAll(res.Body)
|
2019-09-03 12:34:44 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
var resMap map[string]interface{}
|
|
|
|
err = json.Unmarshal(bodyBytes, &resMap)
|
2022-04-14 10:54:49 -05:00
|
|
|
assert.NoError(t, err)
|
2023-02-08 02:32:59 -06:00
|
|
|
assert.Equal(t, "unable to find organization with ID '2'", resMap["error"])
|
|
|
|
assert.Equal(t, "An organization was not found - Please verify your LDAP configuration", resMap["message"])
|
2019-09-03 12:34:44 -05:00
|
|
|
}
|
|
|
|
|
2020-11-13 02:52:38 -06:00
|
|
|
func TestGetUserFromLDAPAPIEndpoint(t *testing.T) {
|
2019-09-03 12:34:44 -05:00
|
|
|
isAdmin := true
|
2023-02-08 02:32:59 -06:00
|
|
|
userSearchResult := &login.ExternalUserInfo{
|
2019-09-03 12:34:44 -05:00
|
|
|
Name: "John Doe",
|
|
|
|
Email: "john.doe@example.com",
|
|
|
|
Login: "johndoe",
|
2019-09-19 10:13:38 -05:00
|
|
|
Groups: []string{"cn=admins,ou=groups,dc=grafana,dc=org", "another-group-not-matched"},
|
2022-08-10 04:56:48 -05:00
|
|
|
OrgRoles: map[int64]org.RoleType{1: org.RoleAdmin},
|
2019-09-03 12:34:44 -05:00
|
|
|
IsGrafanaAdmin: &isAdmin,
|
|
|
|
}
|
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
userSearchConfig := ldap.ServerConfig{
|
2019-09-03 12:34:44 -05:00
|
|
|
Attr: ldap.AttributeMap{
|
|
|
|
Name: "ldap-name",
|
|
|
|
Surname: "ldap-surname",
|
|
|
|
Email: "ldap-email",
|
|
|
|
Username: "ldap-username",
|
|
|
|
},
|
|
|
|
Groups: []*ldap.GroupToOrgRole{
|
|
|
|
{
|
|
|
|
GroupDN: "cn=admins,ou=groups,dc=grafana,dc=org",
|
2019-09-19 10:13:38 -05:00
|
|
|
OrgId: 1,
|
2022-08-10 04:56:48 -05:00
|
|
|
OrgRole: org.RoleAdmin,
|
2019-09-03 12:34:44 -05:00
|
|
|
},
|
2019-11-01 09:42:22 -05:00
|
|
|
{
|
|
|
|
GroupDN: "cn=admins2,ou=groups,dc=grafana,dc=org",
|
|
|
|
OrgId: 1,
|
2022-08-10 04:56:48 -05:00
|
|
|
OrgRole: org.RoleAdmin,
|
2019-11-01 09:42:22 -05:00
|
|
|
},
|
2019-09-03 12:34:44 -05:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2022-09-20 02:55:40 -05:00
|
|
|
mockOrgSearchResult := []*org.OrgDTO{
|
|
|
|
{ID: 1, Name: "Main Org."},
|
2019-09-03 12:34:44 -05:00
|
|
|
}
|
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
_, server := setupAPITest(t, func(a *Service) {
|
|
|
|
a.orgService = &orgtest.FakeOrgService{
|
|
|
|
ExpectedOrgs: mockOrgSearchResult,
|
|
|
|
}
|
2023-02-10 12:01:55 -06:00
|
|
|
a.ldapService = &service.LDAPFakeService{
|
|
|
|
ExpectedClient: &LDAPMock{
|
|
|
|
UserSearchResult: userSearchResult,
|
|
|
|
UserSearchConfig: userSearchConfig,
|
|
|
|
},
|
|
|
|
ExpectedConfig: &ldap.Config{},
|
|
|
|
}
|
2023-02-08 02:32:59 -06:00
|
|
|
})
|
|
|
|
|
|
|
|
req := server.NewGetRequest("/api/admin/ldap/johndoe")
|
|
|
|
webtest.RequestWithSignedInUser(req, &user.SignedInUser{
|
|
|
|
OrgID: 1,
|
|
|
|
Permissions: map[int64]map[string][]string{
|
|
|
|
1: {"ldap.user:read": {"*"}}},
|
|
|
|
})
|
2019-09-03 12:34:44 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
res, err := server.Send(req)
|
|
|
|
defer func() { require.NoError(t, res.Body.Close()) }()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
assert.Equal(t, http.StatusOK, res.StatusCode)
|
2019-09-03 12:34:44 -05:00
|
|
|
|
|
|
|
expected := `
|
|
|
|
{
|
|
|
|
"name": {
|
|
|
|
"cfgAttrValue": "ldap-name", "ldapValue": "John"
|
|
|
|
},
|
|
|
|
"surname": {
|
|
|
|
"cfgAttrValue": "ldap-surname", "ldapValue": "Doe"
|
|
|
|
},
|
|
|
|
"email": {
|
|
|
|
"cfgAttrValue": "ldap-email", "ldapValue": "john.doe@example.com"
|
|
|
|
},
|
|
|
|
"login": {
|
|
|
|
"cfgAttrValue": "ldap-username", "ldapValue": "johndoe"
|
|
|
|
},
|
|
|
|
"isGrafanaAdmin": true,
|
|
|
|
"isDisabled": false,
|
|
|
|
"roles": [
|
2019-09-19 10:13:38 -05:00
|
|
|
{ "orgId": 1, "orgRole": "Admin", "orgName": "Main Org.", "groupDN": "cn=admins,ou=groups,dc=grafana,dc=org" },
|
|
|
|
{ "orgId": 0, "orgRole": "", "orgName": "", "groupDN": "another-group-not-matched" }
|
2019-09-03 12:34:44 -05:00
|
|
|
],
|
|
|
|
"teams": null
|
|
|
|
}
|
|
|
|
`
|
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
bodyBytes, _ := io.ReadAll(res.Body)
|
|
|
|
assert.JSONEq(t, expected, string(bodyBytes))
|
2019-09-04 09:29:14 -05:00
|
|
|
}
|
|
|
|
|
2020-11-13 02:52:38 -06:00
|
|
|
func TestGetUserFromLDAPAPIEndpoint_WithTeamHandler(t *testing.T) {
|
2019-09-08 05:48:47 -05:00
|
|
|
isAdmin := true
|
2023-02-08 02:32:59 -06:00
|
|
|
userSearchResult := &login.ExternalUserInfo{
|
2019-09-08 05:48:47 -05:00
|
|
|
Name: "John Doe",
|
|
|
|
Email: "john.doe@example.com",
|
|
|
|
Login: "johndoe",
|
2019-11-01 09:42:22 -05:00
|
|
|
Groups: []string{"cn=admins,ou=groups,dc=grafana,dc=org"},
|
2022-08-10 04:56:48 -05:00
|
|
|
OrgRoles: map[int64]org.RoleType{1: org.RoleAdmin},
|
2019-09-08 05:48:47 -05:00
|
|
|
IsGrafanaAdmin: &isAdmin,
|
|
|
|
}
|
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
userSearchConfig := ldap.ServerConfig{
|
2019-09-08 05:48:47 -05:00
|
|
|
Attr: ldap.AttributeMap{
|
|
|
|
Name: "ldap-name",
|
|
|
|
Surname: "ldap-surname",
|
|
|
|
Email: "ldap-email",
|
|
|
|
Username: "ldap-username",
|
|
|
|
},
|
|
|
|
Groups: []*ldap.GroupToOrgRole{
|
|
|
|
{
|
|
|
|
GroupDN: "cn=admins,ou=groups,dc=grafana,dc=org",
|
2019-09-19 10:13:38 -05:00
|
|
|
OrgId: 1,
|
2022-08-10 04:56:48 -05:00
|
|
|
OrgRole: org.RoleAdmin,
|
2019-09-08 05:48:47 -05:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2022-09-20 02:55:40 -05:00
|
|
|
mockOrgSearchResult := []*org.OrgDTO{
|
|
|
|
{ID: 1, Name: "Main Org."},
|
2019-09-08 05:48:47 -05:00
|
|
|
}
|
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
_, server := setupAPITest(t, func(a *Service) {
|
|
|
|
a.orgService = &orgtest.FakeOrgService{
|
|
|
|
ExpectedOrgs: mockOrgSearchResult,
|
|
|
|
}
|
2023-02-10 12:01:55 -06:00
|
|
|
a.ldapService = &service.LDAPFakeService{
|
|
|
|
ExpectedClient: &LDAPMock{
|
|
|
|
UserSearchResult: userSearchResult,
|
|
|
|
UserSearchConfig: userSearchConfig,
|
|
|
|
},
|
|
|
|
ExpectedConfig: &ldap.Config{},
|
|
|
|
}
|
2023-02-08 02:32:59 -06:00
|
|
|
})
|
2019-09-08 05:48:47 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
req := server.NewGetRequest("/api/admin/ldap/johndoe")
|
|
|
|
webtest.RequestWithSignedInUser(req, &user.SignedInUser{
|
|
|
|
OrgID: 1,
|
|
|
|
Permissions: map[int64]map[string][]string{
|
|
|
|
1: {"ldap.user:read": {"*"}}},
|
|
|
|
})
|
|
|
|
|
|
|
|
res, err := server.Send(req)
|
|
|
|
defer func() { require.NoError(t, res.Body.Close()) }()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
assert.Equal(t, http.StatusOK, res.StatusCode)
|
2019-09-08 05:48:47 -05:00
|
|
|
|
|
|
|
expected := `
|
|
|
|
{
|
|
|
|
"name": {
|
|
|
|
"cfgAttrValue": "ldap-name", "ldapValue": "John"
|
|
|
|
},
|
|
|
|
"surname": {
|
|
|
|
"cfgAttrValue": "ldap-surname", "ldapValue": "Doe"
|
|
|
|
},
|
|
|
|
"email": {
|
|
|
|
"cfgAttrValue": "ldap-email", "ldapValue": "john.doe@example.com"
|
|
|
|
},
|
|
|
|
"login": {
|
|
|
|
"cfgAttrValue": "ldap-username", "ldapValue": "johndoe"
|
|
|
|
},
|
|
|
|
"isGrafanaAdmin": true,
|
|
|
|
"isDisabled": false,
|
|
|
|
"roles": [
|
|
|
|
{ "orgId": 1, "orgRole": "Admin", "orgName": "Main Org.", "groupDN": "cn=admins,ou=groups,dc=grafana,dc=org" }
|
|
|
|
],
|
2022-02-01 05:03:21 -06:00
|
|
|
"teams": null
|
2019-09-08 05:48:47 -05:00
|
|
|
}
|
|
|
|
`
|
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
bodyBytes, _ := io.ReadAll(res.Body)
|
|
|
|
assert.JSONEq(t, expected, string(bodyBytes))
|
2019-09-08 05:48:47 -05:00
|
|
|
}
|
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
func TestGetLDAPStatusAPIEndpoint(t *testing.T) {
|
2019-09-04 09:29:14 -05:00
|
|
|
pingResult = []*multildap.ServerStatus{
|
|
|
|
{Host: "10.0.0.3", Port: 361, Available: true, Error: nil},
|
|
|
|
{Host: "10.0.0.3", Port: 362, Available: true, Error: nil},
|
|
|
|
{Host: "10.0.0.5", Port: 361, Available: false, Error: errors.New("something is awfully wrong")},
|
|
|
|
}
|
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
_, server := setupAPITest(t, func(a *Service) {
|
2023-02-10 12:01:55 -06:00
|
|
|
a.ldapService = &service.LDAPFakeService{
|
|
|
|
ExpectedClient: &LDAPMock{},
|
|
|
|
ExpectedConfig: &ldap.Config{},
|
|
|
|
}
|
2023-02-08 02:32:59 -06:00
|
|
|
})
|
|
|
|
|
|
|
|
req := server.NewGetRequest("/api/admin/ldap/status")
|
|
|
|
webtest.RequestWithSignedInUser(req, &user.SignedInUser{
|
|
|
|
OrgID: 1,
|
|
|
|
Permissions: map[int64]map[string][]string{
|
|
|
|
1: {"ldap.status:read": {}}},
|
|
|
|
})
|
|
|
|
|
|
|
|
res, err := server.Send(req)
|
|
|
|
defer func() { require.NoError(t, res.Body.Close()) }()
|
|
|
|
require.NoError(t, err)
|
2019-09-04 09:29:14 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
assert.Equal(t, http.StatusOK, res.StatusCode)
|
2019-09-04 09:29:14 -05:00
|
|
|
|
|
|
|
expected := `
|
|
|
|
[
|
|
|
|
{ "host": "10.0.0.3", "port": 361, "available": true, "error": "" },
|
|
|
|
{ "host": "10.0.0.3", "port": 362, "available": true, "error": "" },
|
|
|
|
{ "host": "10.0.0.5", "port": 361, "available": false, "error": "something is awfully wrong" }
|
|
|
|
]
|
|
|
|
`
|
2019-09-13 10:26:25 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
bodyBytes, _ := io.ReadAll(res.Body)
|
|
|
|
assert.JSONEq(t, expected, string(bodyBytes))
|
|
|
|
}
|
2019-09-13 10:26:25 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
func TestPostSyncUserWithLDAPAPIEndpoint_Success(t *testing.T) {
|
|
|
|
userServiceMock := usertest.NewUserServiceFake()
|
|
|
|
userServiceMock.ExpectedUser = &user.User{Login: "ldap-daniel", ID: 34}
|
2019-09-13 10:26:25 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
_, server := setupAPITest(t, func(a *Service) {
|
|
|
|
a.userService = userServiceMock
|
2023-02-10 12:01:55 -06:00
|
|
|
a.ldapService = &service.LDAPFakeService{
|
|
|
|
ExpectedClient: &LDAPMock{UserSearchResult: &login.ExternalUserInfo{
|
|
|
|
Login: "ldap-daniel",
|
|
|
|
}},
|
|
|
|
ExpectedConfig: &ldap.Config{},
|
|
|
|
}
|
2019-09-13 10:26:25 -05:00
|
|
|
})
|
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
req := server.NewPostRequest("/api/admin/ldap/sync/34", nil)
|
|
|
|
webtest.RequestWithSignedInUser(req, &user.SignedInUser{
|
|
|
|
OrgID: 1,
|
|
|
|
Permissions: map[int64]map[string][]string{
|
|
|
|
1: {"ldap.user:sync": {}}},
|
|
|
|
})
|
2019-09-13 10:26:25 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
res, err := server.Send(req)
|
|
|
|
defer func() { require.NoError(t, res.Body.Close()) }()
|
2020-11-13 02:52:38 -06:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
assert.Equal(t, http.StatusOK, res.StatusCode)
|
2019-09-13 10:26:25 -05:00
|
|
|
|
|
|
|
expected := `
|
|
|
|
{
|
|
|
|
"message": "User synced successfully"
|
|
|
|
}
|
|
|
|
`
|
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
bodyBytes, _ := io.ReadAll(res.Body)
|
|
|
|
assert.JSONEq(t, expected, string(bodyBytes))
|
2019-09-13 10:26:25 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestPostSyncUserWithLDAPAPIEndpoint_WhenUserNotFound(t *testing.T) {
|
2022-08-02 09:58:05 -05:00
|
|
|
userServiceMock := usertest.NewUserServiceFake()
|
|
|
|
userServiceMock.ExpectedError = user.ErrUserNotFound
|
2019-09-13 10:26:25 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
_, server := setupAPITest(t, func(a *Service) {
|
|
|
|
a.userService = userServiceMock
|
2023-02-10 12:01:55 -06:00
|
|
|
a.ldapService = &service.LDAPFakeService{
|
|
|
|
ExpectedClient: &LDAPMock{},
|
|
|
|
ExpectedConfig: &ldap.Config{},
|
|
|
|
}
|
2023-02-08 02:32:59 -06:00
|
|
|
})
|
|
|
|
|
|
|
|
req := server.NewPostRequest("/api/admin/ldap/sync/34", nil)
|
|
|
|
webtest.RequestWithSignedInUser(req, &user.SignedInUser{
|
|
|
|
OrgID: 1,
|
|
|
|
Permissions: map[int64]map[string][]string{
|
|
|
|
1: {"ldap.user:sync": {}}},
|
|
|
|
})
|
|
|
|
|
|
|
|
res, err := server.Send(req)
|
|
|
|
defer func() { require.NoError(t, res.Body.Close()) }()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
assert.Equal(t, http.StatusNotFound, res.StatusCode)
|
2019-09-13 10:26:25 -05:00
|
|
|
|
|
|
|
expected := `
|
|
|
|
{
|
2020-11-05 06:07:06 -06:00
|
|
|
"message": "user not found"
|
2019-09-13 10:26:25 -05:00
|
|
|
}
|
|
|
|
`
|
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
bodyBytes, _ := io.ReadAll(res.Body)
|
|
|
|
assert.JSONEq(t, expected, string(bodyBytes))
|
2019-09-13 10:26:25 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestPostSyncUserWithLDAPAPIEndpoint_WhenGrafanaAdmin(t *testing.T) {
|
2022-08-02 09:58:05 -05:00
|
|
|
userServiceMock := usertest.NewUserServiceFake()
|
|
|
|
userServiceMock.ExpectedUser = &user.User{Login: "ldap-daniel", ID: 34}
|
2019-09-13 10:26:25 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
_, server := setupAPITest(t, func(a *Service) {
|
|
|
|
a.userService = userServiceMock
|
|
|
|
a.cfg.AdminUser = "ldap-daniel"
|
2023-02-10 12:01:55 -06:00
|
|
|
a.ldapService = &service.LDAPFakeService{
|
|
|
|
ExpectedClient: &LDAPMock{UserSearchError: multildap.ErrDidNotFindUser},
|
|
|
|
ExpectedConfig: &ldap.Config{},
|
|
|
|
}
|
2023-02-08 02:32:59 -06:00
|
|
|
})
|
2019-09-13 10:26:25 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
req := server.NewPostRequest("/api/admin/ldap/sync/34", nil)
|
|
|
|
webtest.RequestWithSignedInUser(req, &user.SignedInUser{
|
|
|
|
OrgID: 1,
|
|
|
|
Permissions: map[int64]map[string][]string{
|
|
|
|
1: {"ldap.user:sync": {}}},
|
|
|
|
})
|
|
|
|
|
|
|
|
res, err := server.Send(req)
|
|
|
|
defer func() { require.NoError(t, res.Body.Close()) }()
|
|
|
|
require.NoError(t, err)
|
2019-09-13 10:26:25 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
assert.Equal(t, http.StatusBadRequest, res.StatusCode)
|
2019-09-13 10:26:25 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
bodyBytes, _ := io.ReadAll(res.Body)
|
|
|
|
var resMap map[string]interface{}
|
|
|
|
err = json.Unmarshal(bodyBytes, &resMap)
|
2022-04-14 10:54:49 -05:00
|
|
|
assert.NoError(t, err)
|
2023-02-08 02:32:59 -06:00
|
|
|
assert.Equal(t, "did not find a user", resMap["error"])
|
|
|
|
assert.Equal(t, "Refusing to sync grafana super admin \"ldap-daniel\" - it would be disabled", resMap["message"])
|
2019-09-13 10:26:25 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestPostSyncUserWithLDAPAPIEndpoint_WhenUserNotInLDAP(t *testing.T) {
|
2022-08-02 09:58:05 -05:00
|
|
|
userServiceMock := usertest.NewUserServiceFake()
|
|
|
|
userServiceMock.ExpectedUser = &user.User{Login: "ldap-daniel", ID: 34}
|
2019-09-13 10:26:25 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
_, server := setupAPITest(t, func(a *Service) {
|
|
|
|
a.userService = userServiceMock
|
|
|
|
a.authInfoService = &logintest.AuthInfoServiceFake{ExpectedExternalUser: &login.ExternalUserInfo{IsDisabled: true, UserId: 34}}
|
2023-02-10 12:01:55 -06:00
|
|
|
a.ldapService = &service.LDAPFakeService{
|
|
|
|
ExpectedClient: &LDAPMock{UserSearchError: multildap.ErrDidNotFindUser},
|
|
|
|
ExpectedConfig: &ldap.Config{},
|
|
|
|
}
|
2023-02-08 02:32:59 -06:00
|
|
|
})
|
|
|
|
|
|
|
|
req := server.NewPostRequest("/api/admin/ldap/sync/34", nil)
|
|
|
|
webtest.RequestWithSignedInUser(req, &user.SignedInUser{
|
|
|
|
OrgID: 1,
|
|
|
|
Permissions: map[int64]map[string][]string{
|
|
|
|
1: {"ldap.user:sync": {}}},
|
|
|
|
})
|
2019-09-13 10:26:25 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
res, err := server.Send(req)
|
|
|
|
defer func() { require.NoError(t, res.Body.Close()) }()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
assert.Equal(t, http.StatusBadRequest, res.StatusCode)
|
2019-09-13 10:26:25 -05:00
|
|
|
|
|
|
|
expected := `
|
|
|
|
{
|
2019-11-07 07:31:44 -06:00
|
|
|
"message": "User not found in LDAP. Disabled the user without updating information"
|
2019-09-13 10:26:25 -05:00
|
|
|
}
|
|
|
|
`
|
2019-09-04 09:29:14 -05:00
|
|
|
|
2023-02-08 02:32:59 -06:00
|
|
|
bodyBytes, _ := io.ReadAll(res.Body)
|
|
|
|
assert.JSONEq(t, expected, string(bodyBytes))
|
2019-09-03 12:34:44 -05:00
|
|
|
}
|
2021-06-11 08:58:18 -05:00
|
|
|
|
|
|
|
func TestLDAP_AccessControl(t *testing.T) {
|
2023-02-08 02:32:59 -06:00
|
|
|
f, errC := os.CreateTemp("", "ldap.toml")
|
|
|
|
require.NoError(t, errC)
|
|
|
|
|
|
|
|
_, errF := f.WriteString(
|
|
|
|
`[[servers]]
|
|
|
|
host = "127.0.0.1"
|
|
|
|
port = 389
|
|
|
|
search_filter = "(cn=%s)"
|
|
|
|
search_base_dns = ["dc=grafana,dc=org"]`)
|
|
|
|
require.NoError(t, errF)
|
|
|
|
|
2023-02-09 09:31:31 -06:00
|
|
|
ldapConfigFile := f.Name()
|
2023-02-08 02:32:59 -06:00
|
|
|
|
|
|
|
errF = f.Close()
|
|
|
|
require.NoError(t, errF)
|
|
|
|
|
2023-01-19 04:09:26 -06:00
|
|
|
type testCase struct {
|
|
|
|
desc string
|
|
|
|
method string
|
|
|
|
url string
|
|
|
|
expectedCode int
|
|
|
|
permissions []accesscontrol.Permission
|
|
|
|
}
|
|
|
|
tests := []testCase{
|
2021-06-11 08:58:18 -05:00
|
|
|
{
|
|
|
|
url: "/api/admin/ldap/reload",
|
|
|
|
method: http.MethodPost,
|
|
|
|
desc: "ReloadLDAPCfg should return 200 for user with correct permissions",
|
|
|
|
expectedCode: http.StatusOK,
|
2022-06-14 03:17:48 -05:00
|
|
|
permissions: []accesscontrol.Permission{
|
2021-06-11 08:58:18 -05:00
|
|
|
{Action: accesscontrol.ActionLDAPConfigReload},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
url: "/api/admin/ldap/reload",
|
|
|
|
method: http.MethodPost,
|
|
|
|
desc: "ReloadLDAPCfg should return 403 for user without required permissions",
|
|
|
|
expectedCode: http.StatusForbidden,
|
2022-06-14 03:17:48 -05:00
|
|
|
permissions: []accesscontrol.Permission{
|
2021-06-11 08:58:18 -05:00
|
|
|
{Action: "wrong"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
url: "/api/admin/ldap/status",
|
|
|
|
method: http.MethodGet,
|
|
|
|
desc: "GetLDAPStatus should return 200 for user without required permissions",
|
|
|
|
expectedCode: http.StatusOK,
|
2022-06-14 03:17:48 -05:00
|
|
|
permissions: []accesscontrol.Permission{
|
2021-06-11 08:58:18 -05:00
|
|
|
{Action: accesscontrol.ActionLDAPStatusRead},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
url: "/api/admin/ldap/status",
|
|
|
|
method: http.MethodGet,
|
|
|
|
desc: "GetLDAPStatus should return 200 for user without required permissions",
|
|
|
|
expectedCode: http.StatusForbidden,
|
2022-06-14 03:17:48 -05:00
|
|
|
permissions: []accesscontrol.Permission{
|
2021-06-11 08:58:18 -05:00
|
|
|
{Action: "wrong"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
url: "/api/admin/ldap/test",
|
|
|
|
method: http.MethodGet,
|
|
|
|
desc: "GetUserFromLDAP should return 200 for user with required permissions",
|
|
|
|
expectedCode: http.StatusOK,
|
2022-06-14 03:17:48 -05:00
|
|
|
permissions: []accesscontrol.Permission{
|
2021-06-11 08:58:18 -05:00
|
|
|
{Action: accesscontrol.ActionLDAPUsersRead},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
url: "/api/admin/ldap/test",
|
|
|
|
method: http.MethodGet,
|
|
|
|
desc: "GetUserFromLDAP should return 403 for user without required permissions",
|
|
|
|
expectedCode: http.StatusForbidden,
|
2022-06-14 03:17:48 -05:00
|
|
|
permissions: []accesscontrol.Permission{
|
2021-06-11 08:58:18 -05:00
|
|
|
{Action: "wrong"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
2022-01-14 10:55:57 -06:00
|
|
|
url: "/api/admin/ldap/sync/1",
|
2021-06-11 08:58:18 -05:00
|
|
|
method: http.MethodPost,
|
|
|
|
desc: "PostSyncUserWithLDAP should return 200 for user without required permissions",
|
|
|
|
expectedCode: http.StatusOK,
|
2022-06-14 03:17:48 -05:00
|
|
|
permissions: []accesscontrol.Permission{
|
2021-06-11 08:58:18 -05:00
|
|
|
{Action: accesscontrol.ActionLDAPUsersSync},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
2022-01-14 10:55:57 -06:00
|
|
|
url: "/api/admin/ldap/sync/1",
|
2021-06-11 08:58:18 -05:00
|
|
|
method: http.MethodPost,
|
|
|
|
desc: "PostSyncUserWithLDAP should return 200 for user without required permissions",
|
|
|
|
expectedCode: http.StatusForbidden,
|
2022-06-14 03:17:48 -05:00
|
|
|
permissions: []accesscontrol.Permission{
|
2021-06-11 08:58:18 -05:00
|
|
|
{Action: "wrong"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2023-01-19 04:09:26 -06:00
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.desc, func(t *testing.T) {
|
2023-02-08 02:32:59 -06:00
|
|
|
_, server := setupAPITest(t, func(a *Service) {
|
|
|
|
a.userService = &usertest.FakeUserService{ExpectedUser: &user.User{Login: "ldap-daniel", ID: 1}}
|
2023-02-09 09:31:31 -06:00
|
|
|
a.cfg.LDAPConfigFilePath = ldapConfigFile
|
2023-02-10 12:01:55 -06:00
|
|
|
a.ldapService = &service.LDAPFakeService{
|
|
|
|
ExpectedClient: &LDAPMock{UserSearchResult: &login.ExternalUserInfo{
|
|
|
|
Login: "ldap-daniel",
|
|
|
|
}},
|
|
|
|
ExpectedConfig: &ldap.Config{},
|
|
|
|
}
|
2023-01-19 04:09:26 -06:00
|
|
|
})
|
2021-06-11 08:58:18 -05:00
|
|
|
// Add minimal setup to pass handler
|
2023-02-08 02:32:59 -06:00
|
|
|
res, err := server.Send(
|
|
|
|
webtest.RequestWithSignedInUser(server.NewRequest(tt.method, tt.url, nil),
|
|
|
|
userWithPermissions(1, tt.permissions)))
|
2023-01-19 04:09:26 -06:00
|
|
|
require.NoError(t, err)
|
2023-02-08 02:32:59 -06:00
|
|
|
|
|
|
|
bodyBytes, _ := io.ReadAll(res.Body)
|
|
|
|
assert.Equal(t, tt.expectedCode, res.StatusCode, string(bodyBytes))
|
2023-01-19 04:09:26 -06:00
|
|
|
require.NoError(t, res.Body.Close())
|
2021-06-11 08:58:18 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2023-02-08 02:32:59 -06:00
|
|
|
|
|
|
|
func userWithPermissions(orgID int64, permissions []accesscontrol.Permission) *user.SignedInUser {
|
|
|
|
return &user.SignedInUser{OrgID: orgID, OrgRole: org.RoleViewer, Permissions: map[int64]map[string][]string{orgID: accesscontrol.GroupScopesByAction(permissions)}}
|
|
|
|
}
|