mirror of
https://github.com/grafana/grafana.git
synced 2025-07-29 15:52:28 +08:00
Access Control: Add fine-grained access control to ldap handlers (#35525)
* Add new accesscontrol action for ldap config reload * Update ldapAdminEditRole with new ldap config reload permission * wrap /ldap/reload with accesscontrol authorize middleware * document new action and update fixed:ldap:admin:edit with said action * add fake accesscontrol implementation for tests * Add accesscontrol tests for ldap handlers Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com>
This commit is contained in:
@ -4,8 +4,11 @@ import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
@ -573,3 +576,142 @@ func TestPostSyncUserWithLDAPAPIEndpoint_WhenUserNotInLDAP(t *testing.T) {
|
||||
|
||||
assert.JSONEq(t, expected, sc.resp.Body.String())
|
||||
}
|
||||
|
||||
// ***
|
||||
// Access control tests for ldap endpoints
|
||||
// ***
|
||||
|
||||
type ldapAccessControlTestCase struct {
|
||||
expectedCode int
|
||||
desc string
|
||||
url string
|
||||
method string
|
||||
permissions []*accesscontrol.Permission
|
||||
}
|
||||
|
||||
func TestLDAP_AccessControl(t *testing.T) {
|
||||
tests := []ldapAccessControlTestCase{
|
||||
{
|
||||
url: "/api/admin/ldap/reload",
|
||||
method: http.MethodPost,
|
||||
desc: "ReloadLDAPCfg should return 200 for user with correct permissions",
|
||||
expectedCode: http.StatusOK,
|
||||
permissions: []*accesscontrol.Permission{
|
||||
{Action: accesscontrol.ActionLDAPConfigReload},
|
||||
},
|
||||
},
|
||||
{
|
||||
url: "/api/admin/ldap/reload",
|
||||
method: http.MethodPost,
|
||||
desc: "ReloadLDAPCfg should return 403 for user without required permissions",
|
||||
expectedCode: http.StatusForbidden,
|
||||
permissions: []*accesscontrol.Permission{
|
||||
{Action: "wrong"},
|
||||
},
|
||||
},
|
||||
{
|
||||
url: "/api/admin/ldap/status",
|
||||
method: http.MethodGet,
|
||||
desc: "GetLDAPStatus should return 200 for user without required permissions",
|
||||
expectedCode: http.StatusOK,
|
||||
permissions: []*accesscontrol.Permission{
|
||||
{Action: accesscontrol.ActionLDAPStatusRead},
|
||||
},
|
||||
},
|
||||
{
|
||||
url: "/api/admin/ldap/status",
|
||||
method: http.MethodGet,
|
||||
desc: "GetLDAPStatus should return 200 for user without required permissions",
|
||||
expectedCode: http.StatusForbidden,
|
||||
permissions: []*accesscontrol.Permission{
|
||||
{Action: "wrong"},
|
||||
},
|
||||
},
|
||||
{
|
||||
url: "/api/admin/ldap/test",
|
||||
method: http.MethodGet,
|
||||
desc: "GetUserFromLDAP should return 200 for user with required permissions",
|
||||
expectedCode: http.StatusOK,
|
||||
permissions: []*accesscontrol.Permission{
|
||||
{Action: accesscontrol.ActionLDAPUsersRead},
|
||||
},
|
||||
},
|
||||
{
|
||||
url: "/api/admin/ldap/test",
|
||||
method: http.MethodGet,
|
||||
desc: "GetUserFromLDAP should return 403 for user without required permissions",
|
||||
expectedCode: http.StatusForbidden,
|
||||
permissions: []*accesscontrol.Permission{
|
||||
{Action: "wrong"},
|
||||
},
|
||||
},
|
||||
{
|
||||
url: "/api/admin/ldap/sync/test",
|
||||
method: http.MethodPost,
|
||||
desc: "PostSyncUserWithLDAP should return 200 for user without required permissions",
|
||||
expectedCode: http.StatusOK,
|
||||
permissions: []*accesscontrol.Permission{
|
||||
{Action: accesscontrol.ActionLDAPUsersSync},
|
||||
},
|
||||
},
|
||||
{
|
||||
url: "/api/admin/ldap/sync/test",
|
||||
method: http.MethodPost,
|
||||
desc: "PostSyncUserWithLDAP should return 200 for user without required permissions",
|
||||
expectedCode: http.StatusForbidden,
|
||||
permissions: []*accesscontrol.Permission{
|
||||
{Action: "wrong"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
enabled := setting.LDAPEnabled
|
||||
configFile := setting.LDAPConfigFile
|
||||
|
||||
t.Cleanup(func() {
|
||||
setting.LDAPEnabled = enabled
|
||||
setting.LDAPConfigFile = configFile
|
||||
})
|
||||
|
||||
setting.LDAPEnabled = true
|
||||
path, err := filepath.Abs("../../conf/ldap.toml")
|
||||
assert.NoError(t, err)
|
||||
setting.LDAPConfigFile = path
|
||||
|
||||
cfg := setting.NewCfg()
|
||||
cfg.LDAPEnabled = true
|
||||
|
||||
sc := setupAccessControlScenarioContext(t, cfg, test.url, test.permissions)
|
||||
sc.resp = httptest.NewRecorder()
|
||||
sc.req, err = http.NewRequest(test.method, test.url, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Add minimal setup to pass handler
|
||||
userSearchResult = &models.ExternalUserInfo{}
|
||||
userSearchError = nil
|
||||
newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
|
||||
return &LDAPMock{}
|
||||
}
|
||||
|
||||
bus.AddHandler("test", func(q *models.GetUserByIdQuery) error {
|
||||
q.Result = &models.User{}
|
||||
return nil
|
||||
})
|
||||
|
||||
bus.AddHandler("test", func(q *models.GetAuthInfoQuery) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
bus.AddHandler("test", func(cmd *models.UpsertUserCommand) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.exec()
|
||||
assert.Equal(t, test.expectedCode, sc.resp.Code)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user