Browse Source

feat(ldap): more work on org role sync

Torkel Ödegaard 10 years ago
parent
commit
42670c27d5
3 changed files with 94 additions and 9 deletions
  1. 47 2
      pkg/auth/ldap.go
  2. 43 5
      pkg/auth/ldap_test.go
  3. 4 2
      pkg/auth/settings.go

+ 47 - 2
pkg/auth/ldap.go

@@ -27,7 +27,7 @@ func init() {
 			SearchFilter:  "(cn=%s)",
 			SearchFilter:  "(cn=%s)",
 			SearchBaseDNs: []string{"dc=grafana,dc=org"},
 			SearchBaseDNs: []string{"dc=grafana,dc=org"},
 			LdapGroups: []*LdapGroupToOrgRole{
 			LdapGroups: []*LdapGroupToOrgRole{
-				{GroupDN: "cn=users,dc=grafana,dc=org", OrgRole: "Editor"},
+				{GroupDN: "cn=users,dc=grafana,dc=org", OrgRole: m.ROLE_EDITOR},
 			},
 			},
 		},
 		},
 	}
 	}
@@ -89,7 +89,9 @@ func (a *ldapAuther) login(query *AuthenticateUserQuery) error {
 
 
 func (a *ldapAuther) getGrafanaUserFor(ldapUser *ldapUserInfo) (*m.User, error) {
 func (a *ldapAuther) getGrafanaUserFor(ldapUser *ldapUserInfo) (*m.User, error) {
 	// validate that the user has access
 	// validate that the user has access
-	access := false
+	// if there are no ldap group mappings access is true
+	// otherwise a single group must match
+	access := len(a.server.LdapGroups) == 0
 	for _, ldapGroup := range a.server.LdapGroups {
 	for _, ldapGroup := range a.server.LdapGroups {
 		if ldapUser.isMemberOf(ldapGroup.GroupDN) {
 		if ldapUser.isMemberOf(ldapGroup.GroupDN) {
 			access = true
 			access = true
@@ -129,6 +131,49 @@ func (a *ldapAuther) createGrafanaUser(ldapUser *ldapUserInfo) (*m.User, error)
 }
 }
 
 
 func (a *ldapAuther) syncOrgRoles(user *m.User, ldapUser *ldapUserInfo) error {
 func (a *ldapAuther) syncOrgRoles(user *m.User, ldapUser *ldapUserInfo) error {
+	if len(a.server.LdapGroups) == 0 {
+		return nil
+	}
+
+	orgsQuery := m.GetUserOrgListQuery{UserId: user.Id}
+	if err := bus.Dispatch(&orgsQuery); err != nil {
+		return err
+	}
+
+	// remove or update org roles
+	for _, org := range orgsQuery.Result {
+		for _, group := range a.server.LdapGroups {
+			if group.OrgId == org.OrgId && ldapUser.isMemberOf(group.GroupDN) {
+				if org.Role != group.OrgRole {
+					// update role
+				}
+			} else {
+				// remove role
+			}
+		}
+	}
+
+	for _, group := range a.server.LdapGroups {
+		if !ldapUser.isMemberOf(group.GroupDN) {
+			continue
+		}
+
+		match := false
+		for _, org := range orgsQuery.Result {
+			if group.OrgId == org.OrgId {
+				match = true
+			}
+		}
+
+		if !match {
+			// add role
+			cmd := m.AddOrgUserCommand{UserId: user.Id, Role: group.OrgRole, OrgId: group.OrgId}
+			if err := bus.Dispatch(&cmd); err != nil {
+				return err
+			}
+		}
+	}
+
 	return nil
 	return nil
 }
 }
 
 

+ 43 - 5
pkg/auth/ldap_test.go

@@ -13,7 +13,9 @@ func TestLdapAuther(t *testing.T) {
 	Convey("When translating ldap user to grafana user", t, func() {
 	Convey("When translating ldap user to grafana user", t, func() {
 
 
 		Convey("Given no ldap group map match", func() {
 		Convey("Given no ldap group map match", func() {
-			ldapAuther := NewLdapAuthenticator(&LdapServerConf{})
+			ldapAuther := NewLdapAuthenticator(&LdapServerConf{
+				LdapGroups: []*LdapGroupToOrgRole{{}},
+			})
 			_, err := ldapAuther.getGrafanaUserFor(&ldapUserInfo{})
 			_, err := ldapAuther.getGrafanaUserFor(&ldapUserInfo{})
 
 
 			So(err, ShouldEqual, ErrInvalidCredentials)
 			So(err, ShouldEqual, ErrInvalidCredentials)
@@ -24,7 +26,7 @@ func TestLdapAuther(t *testing.T) {
 		ldapAutherScenario("Given wildcard group match", func(sc *scenarioContext) {
 		ldapAutherScenario("Given wildcard group match", func(sc *scenarioContext) {
 			ldapAuther := NewLdapAuthenticator(&LdapServerConf{
 			ldapAuther := NewLdapAuthenticator(&LdapServerConf{
 				LdapGroups: []*LdapGroupToOrgRole{
 				LdapGroups: []*LdapGroupToOrgRole{
-					{GroupDN: "*", OrgRole: "Admin", OrgName: "Main"},
+					{GroupDN: "*", OrgRole: "Admin"},
 				},
 				},
 			})
 			})
 
 
@@ -38,7 +40,7 @@ func TestLdapAuther(t *testing.T) {
 		ldapAutherScenario("Given exact group match", func(sc *scenarioContext) {
 		ldapAutherScenario("Given exact group match", func(sc *scenarioContext) {
 			ldapAuther := NewLdapAuthenticator(&LdapServerConf{
 			ldapAuther := NewLdapAuthenticator(&LdapServerConf{
 				LdapGroups: []*LdapGroupToOrgRole{
 				LdapGroups: []*LdapGroupToOrgRole{
-					{GroupDN: "cn=users", OrgRole: "Admin", OrgName: "Main"},
+					{GroupDN: "cn=users", OrgRole: "Admin"},
 				},
 				},
 			})
 			})
 
 
@@ -52,7 +54,7 @@ func TestLdapAuther(t *testing.T) {
 		ldapAutherScenario("Given no existing grafana user", func(sc *scenarioContext) {
 		ldapAutherScenario("Given no existing grafana user", func(sc *scenarioContext) {
 			ldapAuther := NewLdapAuthenticator(&LdapServerConf{
 			ldapAuther := NewLdapAuthenticator(&LdapServerConf{
 				LdapGroups: []*LdapGroupToOrgRole{
 				LdapGroups: []*LdapGroupToOrgRole{
-					{GroupDN: "cn=users", OrgRole: "Admin", OrgName: "Main"},
+					{GroupDN: "cn=users", OrgRole: "Admin"},
 				},
 				},
 			})
 			})
 
 
@@ -78,6 +80,28 @@ func TestLdapAuther(t *testing.T) {
 		})
 		})
 
 
 	})
 	})
+
+	Convey("When syncing ldap groups to grafana org roles", t, func() {
+
+		ldapAutherScenario("given no current user orgs", func(sc *scenarioContext) {
+			ldapAuther := NewLdapAuthenticator(&LdapServerConf{
+				LdapGroups: []*LdapGroupToOrgRole{
+					{GroupDN: "cn=users", OrgRole: "Admin"},
+				},
+			})
+
+			sc.userOrgsQueryReturns([]*m.UserOrgDTO{})
+			err := ldapAuther.syncOrgRoles(&m.User{}, &ldapUserInfo{
+				MemberOf: []string{"cn=users"},
+			})
+
+			Convey("Should create new org user", func() {
+				So(err, ShouldBeNil)
+				So(sc.addOrgUserCommand, ShouldNotBeNil)
+				So(sc.addOrgUserCommand.Role, ShouldEqual, m.ROLE_ADMIN)
+			})
+		})
+	})
 }
 }
 
 
 func ldapAutherScenario(desc string, fn scenarioFunc) {
 func ldapAutherScenario(desc string, fn scenarioFunc) {
@@ -85,18 +109,25 @@ func ldapAutherScenario(desc string, fn scenarioFunc) {
 		defer bus.ClearBusHandlers()
 		defer bus.ClearBusHandlers()
 
 
 		sc := &scenarioContext{}
 		sc := &scenarioContext{}
+
 		bus.AddHandler("test", func(cmd *m.CreateUserCommand) error {
 		bus.AddHandler("test", func(cmd *m.CreateUserCommand) error {
 			sc.createUserCmd = cmd
 			sc.createUserCmd = cmd
 			sc.createUserCmd.Result = m.User{Login: cmd.Login}
 			sc.createUserCmd.Result = m.User{Login: cmd.Login}
 			return nil
 			return nil
 		})
 		})
 
 
+		bus.AddHandler("test", func(cmd *m.AddOrgUserCommand) error {
+			sc.addOrgUserCommand = cmd
+			return nil
+		})
+
 		fn(sc)
 		fn(sc)
 	})
 	})
 }
 }
 
 
 type scenarioContext struct {
 type scenarioContext struct {
-	createUserCmd *m.CreateUserCommand
+	createUserCmd     *m.CreateUserCommand
+	addOrgUserCommand *m.AddOrgUserCommand
 }
 }
 
 
 func (sc *scenarioContext) userQueryReturns(user *m.User) {
 func (sc *scenarioContext) userQueryReturns(user *m.User) {
@@ -110,4 +141,11 @@ func (sc *scenarioContext) userQueryReturns(user *m.User) {
 	})
 	})
 }
 }
 
 
+func (sc *scenarioContext) userOrgsQueryReturns(orgs []*m.UserOrgDTO) {
+	bus.AddHandler("test", func(query *m.GetUserOrgListQuery) error {
+		query.Result = orgs
+		return nil
+	})
+}
+
 type scenarioFunc func(c *scenarioContext)
 type scenarioFunc func(c *scenarioContext)

+ 4 - 2
pkg/auth/settings.go

@@ -1,9 +1,11 @@
 package auth
 package auth
 
 
+import m "github.com/grafana/grafana/pkg/models"
+
 type LdapGroupToOrgRole struct {
 type LdapGroupToOrgRole struct {
 	GroupDN string
 	GroupDN string
-	OrgId   int
-	OrgRole string
+	OrgId   int64
+	OrgRole m.RoleType
 }
 }
 
 
 type LdapServerConf struct {
 type LdapServerConf struct {