2019-06-13 09:47:52 -05:00
|
|
|
package ldap
|
|
|
|
|
|
|
|
import (
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
|
|
|
"github.com/grafana/grafana/pkg/models"
|
2019-09-19 10:13:38 -05:00
|
|
|
. "github.com/smartystreets/goconvey/convey"
|
|
|
|
"gopkg.in/ldap.v3"
|
2019-06-13 09:47:52 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestLDAPPrivateMethods(t *testing.T) {
|
2019-07-24 04:49:18 -05:00
|
|
|
Convey("getSearchRequest()", t, func() {
|
|
|
|
Convey("with enabled GroupSearchFilterUserAttribute setting", func() {
|
|
|
|
server := &Server{
|
|
|
|
Config: &ServerConfig{
|
|
|
|
Attr: AttributeMap{
|
|
|
|
Username: "username",
|
|
|
|
Name: "name",
|
|
|
|
MemberOf: "memberof",
|
|
|
|
Email: "email",
|
|
|
|
},
|
|
|
|
GroupSearchFilterUserAttribute: "gansta",
|
|
|
|
SearchBaseDNs: []string{"BaseDNHere"},
|
|
|
|
},
|
|
|
|
log: log.New("test-logger"),
|
|
|
|
}
|
|
|
|
|
|
|
|
result := server.getSearchRequest("killa", []string{"gorilla"})
|
|
|
|
|
|
|
|
So(result, ShouldResemble, &ldap.SearchRequest{
|
|
|
|
BaseDN: "killa",
|
|
|
|
Scope: 2,
|
|
|
|
DerefAliases: 0,
|
|
|
|
SizeLimit: 0,
|
|
|
|
TimeLimit: 0,
|
|
|
|
TypesOnly: false,
|
|
|
|
Filter: "(|)",
|
|
|
|
Attributes: []string{
|
|
|
|
"username",
|
|
|
|
"email",
|
|
|
|
"name",
|
|
|
|
"memberof",
|
|
|
|
"gansta",
|
|
|
|
},
|
|
|
|
Controls: nil,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2019-06-13 09:47:52 -05:00
|
|
|
Convey("serializeUsers()", t, func() {
|
|
|
|
Convey("simple case", func() {
|
|
|
|
server := &Server{
|
|
|
|
Config: &ServerConfig{
|
|
|
|
Attr: AttributeMap{
|
|
|
|
Username: "username",
|
|
|
|
Name: "name",
|
|
|
|
MemberOf: "memberof",
|
|
|
|
Email: "email",
|
|
|
|
},
|
|
|
|
SearchBaseDNs: []string{"BaseDNHere"},
|
|
|
|
},
|
|
|
|
Connection: &MockConnection{},
|
|
|
|
log: log.New("test-logger"),
|
|
|
|
}
|
|
|
|
|
|
|
|
entry := ldap.Entry{
|
|
|
|
DN: "dn",
|
|
|
|
Attributes: []*ldap.EntryAttribute{
|
|
|
|
{Name: "username", Values: []string{"roelgerrits"}},
|
|
|
|
{Name: "surname", Values: []string{"Gerrits"}},
|
|
|
|
{Name: "email", Values: []string{"roel@test.com"}},
|
|
|
|
{Name: "name", Values: []string{"Roel"}},
|
|
|
|
{Name: "memberof", Values: []string{"admins"}},
|
|
|
|
},
|
|
|
|
}
|
LDAP: Divide the requests (#17885)
* LDAP: Divide the requests
Active Directory does indeed have a limitation with 1000 results
per search (default of course).
However, that limitation can be workaround with the pagination search feature,
meaning `pagination` number is how many times LDAP compatible server will be
requested by the client with specified amount of users (like 1000). That feature
already embeded with LDAP compatible client (including our `go-ldap`).
But slapd server has by default stricter settings. First, limitation is not 1000
but 500, second, pagination workaround presumably (information about it a bit
scarce and I still not sure on some of the details from my own testing)
cannot be workaround with pagination feature.
See
https://www.openldap.org/doc/admin24/limits.html
https://serverfault.com/questions/328671/paging-using-ldapsearch
hashicorp/vault#4162 - not sure why they were hitting the limit in
the first place, since `go-ldap` doesn't have one by default.
But, given all that, for me `ldapsearch` command with same request
as with `go-ldap` still returns more then 500 results, it can even return
as much as 10500 items (probably more).
So either there is some differences with implementation of the LDAP search
between `go-ldap` module and `ldapsearch` or I am missing a step :/.
In the wild (see serverfault link), apparently, people still hitting that
limitation even with `ldapsearch`, so it still seems to be an issue.
But, nevertheless, I'm still confused by this incoherence.
To workaround it, I divide the request by no more then
500 items per search
2019-07-03 09:39:54 -05:00
|
|
|
users := []*ldap.Entry{&entry}
|
2019-06-13 09:47:52 -05:00
|
|
|
|
|
|
|
result, err := server.serializeUsers(users)
|
|
|
|
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(result[0].Login, ShouldEqual, "roelgerrits")
|
|
|
|
So(result[0].Email, ShouldEqual, "roel@test.com")
|
|
|
|
So(result[0].Groups, ShouldContain, "admins")
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("without lastname", func() {
|
|
|
|
server := &Server{
|
|
|
|
Config: &ServerConfig{
|
|
|
|
Attr: AttributeMap{
|
|
|
|
Username: "username",
|
|
|
|
Name: "name",
|
|
|
|
MemberOf: "memberof",
|
|
|
|
Email: "email",
|
|
|
|
},
|
|
|
|
SearchBaseDNs: []string{"BaseDNHere"},
|
|
|
|
},
|
|
|
|
Connection: &MockConnection{},
|
|
|
|
log: log.New("test-logger"),
|
|
|
|
}
|
|
|
|
|
|
|
|
entry := ldap.Entry{
|
|
|
|
DN: "dn",
|
|
|
|
Attributes: []*ldap.EntryAttribute{
|
|
|
|
{Name: "username", Values: []string{"roelgerrits"}},
|
|
|
|
{Name: "email", Values: []string{"roel@test.com"}},
|
|
|
|
{Name: "name", Values: []string{"Roel"}},
|
|
|
|
{Name: "memberof", Values: []string{"admins"}},
|
|
|
|
},
|
|
|
|
}
|
LDAP: Divide the requests (#17885)
* LDAP: Divide the requests
Active Directory does indeed have a limitation with 1000 results
per search (default of course).
However, that limitation can be workaround with the pagination search feature,
meaning `pagination` number is how many times LDAP compatible server will be
requested by the client with specified amount of users (like 1000). That feature
already embeded with LDAP compatible client (including our `go-ldap`).
But slapd server has by default stricter settings. First, limitation is not 1000
but 500, second, pagination workaround presumably (information about it a bit
scarce and I still not sure on some of the details from my own testing)
cannot be workaround with pagination feature.
See
https://www.openldap.org/doc/admin24/limits.html
https://serverfault.com/questions/328671/paging-using-ldapsearch
hashicorp/vault#4162 - not sure why they were hitting the limit in
the first place, since `go-ldap` doesn't have one by default.
But, given all that, for me `ldapsearch` command with same request
as with `go-ldap` still returns more then 500 results, it can even return
as much as 10500 items (probably more).
So either there is some differences with implementation of the LDAP search
between `go-ldap` module and `ldapsearch` or I am missing a step :/.
In the wild (see serverfault link), apparently, people still hitting that
limitation even with `ldapsearch`, so it still seems to be an issue.
But, nevertheless, I'm still confused by this incoherence.
To workaround it, I divide the request by no more then
500 items per search
2019-07-03 09:39:54 -05:00
|
|
|
users := []*ldap.Entry{&entry}
|
2019-06-13 09:47:52 -05:00
|
|
|
|
|
|
|
result, err := server.serializeUsers(users)
|
|
|
|
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
So(result[0].Name, ShouldEqual, "Roel")
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("validateGrafanaUser()", t, func() {
|
|
|
|
Convey("Returns error when user does not belong in any of the specified LDAP groups", func() {
|
|
|
|
server := &Server{
|
|
|
|
Config: &ServerConfig{
|
|
|
|
Groups: []*GroupToOrgRole{
|
|
|
|
{
|
2019-09-19 10:13:38 -05:00
|
|
|
OrgId: 1,
|
2019-06-13 09:47:52 -05:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
log: logger.New("test"),
|
|
|
|
}
|
|
|
|
|
|
|
|
user := &models.ExternalUserInfo{
|
|
|
|
Login: "markelog",
|
|
|
|
}
|
|
|
|
|
|
|
|
result := server.validateGrafanaUser(user)
|
|
|
|
|
|
|
|
So(result, ShouldEqual, ErrInvalidCredentials)
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("Does not return error when group config is empty", func() {
|
|
|
|
server := &Server{
|
|
|
|
Config: &ServerConfig{
|
|
|
|
Groups: []*GroupToOrgRole{},
|
|
|
|
},
|
|
|
|
log: logger.New("test"),
|
|
|
|
}
|
|
|
|
|
|
|
|
user := &models.ExternalUserInfo{
|
|
|
|
Login: "markelog",
|
|
|
|
}
|
|
|
|
|
|
|
|
result := server.validateGrafanaUser(user)
|
|
|
|
|
|
|
|
So(result, ShouldBeNil)
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("Does not return error when groups are there", func() {
|
|
|
|
server := &Server{
|
|
|
|
Config: &ServerConfig{
|
|
|
|
Groups: []*GroupToOrgRole{
|
|
|
|
{
|
2019-09-19 10:13:38 -05:00
|
|
|
OrgId: 1,
|
2019-06-13 09:47:52 -05:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
log: logger.New("test"),
|
|
|
|
}
|
|
|
|
|
|
|
|
user := &models.ExternalUserInfo{
|
|
|
|
Login: "markelog",
|
|
|
|
OrgRoles: map[int64]models.RoleType{
|
|
|
|
1: "test",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
result := server.validateGrafanaUser(user)
|
|
|
|
|
|
|
|
So(result, ShouldBeNil)
|
|
|
|
})
|
|
|
|
})
|
2019-07-05 09:49:00 -05:00
|
|
|
|
2019-08-02 11:24:44 -05:00
|
|
|
Convey("shouldAdminBind()", t, func() {
|
2019-07-10 05:25:21 -05:00
|
|
|
Convey("it should require admin userBind", func() {
|
2019-07-05 09:49:00 -05:00
|
|
|
server := &Server{
|
|
|
|
Config: &ServerConfig{
|
|
|
|
BindPassword: "test",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2019-08-02 11:24:44 -05:00
|
|
|
result := server.shouldAdminBind()
|
2019-07-05 09:49:00 -05:00
|
|
|
So(result, ShouldBeTrue)
|
|
|
|
})
|
|
|
|
|
2019-07-10 05:25:21 -05:00
|
|
|
Convey("it should not require admin userBind", func() {
|
2019-07-05 09:49:00 -05:00
|
|
|
server := &Server{
|
|
|
|
Config: &ServerConfig{
|
|
|
|
BindPassword: "",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2019-08-02 11:24:44 -05:00
|
|
|
result := server.shouldAdminBind()
|
2019-07-05 09:49:00 -05:00
|
|
|
So(result, ShouldBeFalse)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2019-08-02 11:24:44 -05:00
|
|
|
Convey("shouldSingleBind()", t, func() {
|
|
|
|
Convey("it should allow single bind", func() {
|
|
|
|
server := &Server{
|
|
|
|
Config: &ServerConfig{
|
|
|
|
BindDN: "cn=%s,dc=grafana,dc=org",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
result := server.shouldSingleBind()
|
|
|
|
So(result, ShouldBeTrue)
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("it should not allow single bind", func() {
|
|
|
|
server := &Server{
|
|
|
|
Config: &ServerConfig{
|
|
|
|
BindDN: "cn=admin,dc=grafana,dc=org",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
result := server.shouldSingleBind()
|
|
|
|
So(result, ShouldBeFalse)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("singleBindDN()", t, func() {
|
|
|
|
Convey("it should allow single bind", func() {
|
|
|
|
server := &Server{
|
|
|
|
Config: &ServerConfig{
|
|
|
|
BindDN: "cn=%s,dc=grafana,dc=org",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
result := server.singleBindDN("test")
|
|
|
|
So(result, ShouldEqual, "cn=test,dc=grafana,dc=org")
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2019-06-13 09:47:52 -05:00
|
|
|
}
|