Commit a7b1df34 by Torkel Ödegaard

feat(ldap): more unit tests for ldap to grafana user sync

parent 2fa9311e
......@@ -30,7 +30,7 @@ func AuthenticateUser(query *AuthenticateUserQuery) error {
}
if setting.LdapEnabled {
for _, server := range setting.LdapServers {
for _, server := range ldapServers {
auther := NewLdapAuthenticator(server)
err = auther.login(query)
if err == nil || err != ErrInvalidCredentials {
......
......@@ -8,12 +8,13 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/log"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
)
var ldapServers []*LdapServerConf
func init() {
setting.LdapServers = []*setting.LdapServerConf{
&setting.LdapServerConf{
ldapServers = []*LdapServerConf{
{
UseSSL: false,
Host: "127.0.0.1",
Port: "389",
......@@ -25,45 +26,20 @@ func init() {
AttrEmail: "email",
SearchFilter: "(cn=%s)",
SearchBaseDNs: []string{"dc=grafana,dc=org"},
LdapGroups: []*LdapGroupToOrgRole{
{GroupDN: "cn=users,dc=grafana,dc=org", OrgName: "Main Org.", OrgRole: "Editor"},
},
},
}
}
type ldapAuther struct {
server *setting.LdapServerConf
server *LdapServerConf
conn *ldap.Conn
}
type ldapUserInfo struct {
FirstName string
LastName string
Username string
Email string
MemberOf []string
}
func (u *ldapUserInfo) isMemberOfAny(groups []string) bool {
for _, group := range groups {
if u.isMemberOf(group) {
return true
}
}
return false
}
func (u *ldapUserInfo) isMemberOf(group string) bool {
for _, member := range u.MemberOf {
if member == group {
return true
}
}
return false
}
func NewLdapAuthenticator(server *setting.LdapServerConf) *ldapAuther {
return &ldapAuther{
server: server,
}
func NewLdapAuthenticator(server *LdapServerConf) *ldapAuther {
return &ldapAuther{server: server}
}
func (a *ldapAuther) Dial() error {
......@@ -108,11 +84,26 @@ func (a *ldapAuther) login(query *AuthenticateUserQuery) error {
}
func (a *ldapAuther) getGrafanaUserFor(ldapUser *ldapUserInfo) (*m.User, error) {
// validate that the user has access
access := false
for _, ldapGroup := range a.server.LdapGroups {
if ldapUser.isMemberOf(ldapGroup.GroupDN) {
access = true
}
}
if !access {
log.Info("Ldap Auth: user %s does not belong in any of the specified ldap groups", ldapUser.Username)
return nil, ErrInvalidCredentials
}
// get user from grafana db
userQuery := m.GetUserByLoginQuery{LoginOrEmail: ldapUser.Username}
if err := bus.Dispatch(&userQuery); err != nil {
if err == m.ErrUserNotFound {
return a.createGrafanaUser(ldapUser)
} else {
return nil, err
}
}
......@@ -221,5 +212,4 @@ func getLdapAttrArray(name string, result *ldap.SearchResult) []string {
func createUserFromLdapInfo() error {
return nil
}
package auth
import (
"testing"
"github.com/grafana/grafana/pkg/bus"
m "github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
)
func TestLdapAuther(t *testing.T) {
Convey("When translating ldap user to grafana user", t, func() {
Convey("Given no ldap group map match", func() {
ldapAuther := NewLdapAuthenticator(&LdapServerConf{})
_, err := ldapAuther.getGrafanaUserFor(&ldapUserInfo{})
So(err, ShouldEqual, ErrInvalidCredentials)
})
var user1 = &m.User{}
ldapAutherScenario("Given wildcard group match", func(sc *scenarioContext) {
ldapAuther := NewLdapAuthenticator(&LdapServerConf{
LdapGroups: []*LdapGroupToOrgRole{
{GroupDN: "*", OrgRole: "Admin", OrgName: "Main"},
},
})
sc.userQueryReturns(user1)
result, err := ldapAuther.getGrafanaUserFor(&ldapUserInfo{})
So(err, ShouldBeNil)
So(result, ShouldEqual, user1)
})
ldapAutherScenario("Given exact group match", func(sc *scenarioContext) {
ldapAuther := NewLdapAuthenticator(&LdapServerConf{
LdapGroups: []*LdapGroupToOrgRole{
{GroupDN: "cn=users", OrgRole: "Admin", OrgName: "Main"},
},
})
sc.userQueryReturns(user1)
result, err := ldapAuther.getGrafanaUserFor(&ldapUserInfo{MemberOf: []string{"cn=users"}})
So(err, ShouldBeNil)
So(result, ShouldEqual, user1)
})
ldapAutherScenario("Given no existing grafana user", func(sc *scenarioContext) {
ldapAuther := NewLdapAuthenticator(&LdapServerConf{
LdapGroups: []*LdapGroupToOrgRole{
{GroupDN: "cn=users", OrgRole: "Admin", OrgName: "Main"},
},
})
sc.userQueryReturns(nil)
result, err := ldapAuther.getGrafanaUserFor(&ldapUserInfo{
Username: "torkelo",
Email: "my@email.com",
MemberOf: []string{"cn=users"},
})
So(err, ShouldBeNil)
Convey("Should create new user", func() {
So(sc.createUserCmd.Login, ShouldEqual, "torkelo")
So(sc.createUserCmd.Email, ShouldEqual, "my@email.com")
})
Convey("Should return new user", func() {
So(result.Login, ShouldEqual, "torkelo")
})
})
})
}
func ldapAutherScenario(desc string, fn scenarioFunc) {
Convey(desc, func() {
defer bus.ClearBusHandlers()
sc := &scenarioContext{}
bus.AddHandler("test", func(cmd *m.CreateUserCommand) error {
sc.createUserCmd = cmd
sc.createUserCmd.Result = m.User{Login: cmd.Login}
return nil
})
fn(sc)
})
}
type scenarioContext struct {
createUserCmd *m.CreateUserCommand
}
func (sc *scenarioContext) userQueryReturns(user *m.User) {
bus.AddHandler("test", func(query *m.GetUserByLoginQuery) error {
if user == nil {
return m.ErrUserNotFound
} else {
query.Result = user
return nil
}
})
}
type scenarioFunc func(c *scenarioContext)
package auth
type ldapUserInfo struct {
FirstName string
LastName string
Username string
Email string
MemberOf []string
}
func (u *ldapUserInfo) isMemberOf(group string) bool {
if group == "*" {
return true
}
for _, member := range u.MemberOf {
if member == group {
return true
}
}
return false
}
package setting
package auth
type LdapGroupToOrgRole struct {
LdapGroupPath string
OrgId int
OrgRole string
GroupDN string
OrgId int
OrgName string
OrgRole string
}
type LdapServerConf struct {
......@@ -21,5 +22,5 @@ type LdapServerConf struct {
SearchFilter string
SearchBaseDNs []string
LdapGroups []LdapGroupToOrgRole
LdapGroups []*LdapGroupToOrgRole
}
......@@ -119,7 +119,6 @@ var (
// LDAP
LdapEnabled bool
LdapServers []*LdapServerConf
// SMTP email settings
Smtp SmtpSettings
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment