From c204786a6c8428a7202fa2d4a64ef8475d1c8061 Mon Sep 17 00:00:00 2001 From: Gregory Ballantine Date: Mon, 22 Jul 2019 15:42:13 -0400 Subject: [PATCH] Added a group deleteMember subcommand; cleaned up some style issues --- cmd/group/add.go | 7 ++- cmd/group/addMember.go | 5 +- cmd/group/deleteMember.go | 99 +++++++++++++++++++++++++++++++++++++++ cmd/group/group.go | 10 ++-- 4 files changed, 109 insertions(+), 12 deletions(-) create mode 100644 cmd/group/deleteMember.go diff --git a/cmd/group/add.go b/cmd/group/add.go index d702772..f37ac95 100644 --- a/cmd/group/add.go +++ b/cmd/group/add.go @@ -1,7 +1,6 @@ package group import ( - "errors" "fmt" "log" "os" @@ -21,7 +20,7 @@ func init() { groupAddCmd.Flags().StringP("id_attribute", "a", "cn", "LDAP DN attribute for groups") groupAddCmd.Flags().StringVarP(&flagGroupName, "group_name", "n", "", "Name for the new group") groupAddCmd.Flags().StringVarP(&flagGroupType, "group_type", "t", "unix", "Type of the new group") - groupAddCmd.Flags().IntVarP(&flagGroupIdNumber, "group_id", "i", -1, "ID number of the new group (Unix/Posix groups only)") + groupAddCmd.Flags().IntVarP(&flagGroupIDNumber, "group_id", "i", -1, "ID number of the new group (Unix/Posix groups only)") groupAddCmd.Flags().StringVarP(&flagGroupMembers, "group_members", "m", "", "Members to add to the newly created group") // bind config file values to group add flags viper.BindPFlag("group.base_ou", groupAddCmd.Flags().Lookup("base_ou")) @@ -36,7 +35,7 @@ var groupAddCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { // check the type given if !util.ContainsString(validTypes, flagGroupType) { - log.Fatal(errors.New(fmt.Sprintf("%s is not a valid group type; valid types are: %v", flagGroupType, validTypes))) + log.Fatal(fmt.Errorf("%s is not a valid group type; valid types are: %v", flagGroupType, validTypes)) os.Exit(1) } @@ -69,7 +68,7 @@ var groupAddCmd = &cobra.Command{ // finish adding attributes to the request addRequest.Attribute("objectClass", groupOClasses) - addRequest.Attribute("gidNumber", []string{strconv.Itoa(flagGroupIdNumber)}) + addRequest.Attribute("gidNumber", []string{strconv.Itoa(flagGroupIDNumber)}) if flagGroupMembers != "" { addRequest.Attribute("memberUid", strings.Split(flagGroupMembers, ",")) diff --git a/cmd/group/addMember.go b/cmd/group/addMember.go index a052b4d..bcc4156 100644 --- a/cmd/group/addMember.go +++ b/cmd/group/addMember.go @@ -1,7 +1,6 @@ package group import ( - "errors" "fmt" "log" "os" @@ -34,13 +33,13 @@ var groupAddMemberCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { // check the type given if !util.ContainsString(validTypes, flagGroupType) { - log.Fatal(errors.New(fmt.Sprintf("%s is not a valid group type; valid types are: %v", flagGroupType, validTypes))) + log.Fatal(fmt.Errorf("%s is not a valid group type; valid types are: %v", flagGroupType, validTypes)) os.Exit(1) } // check if users were supplied if flagGroupMembers == "" { - log.Fatal(errors.New(fmt.Sprintf("You didn't supply any members to add to the group!"))) + log.Fatal(fmt.Errorf("you didn't supply any members to add to the group")) os.Exit(1) } diff --git a/cmd/group/deleteMember.go b/cmd/group/deleteMember.go new file mode 100644 index 0000000..dbe3f1a --- /dev/null +++ b/cmd/group/deleteMember.go @@ -0,0 +1,99 @@ +package group + +import ( + "fmt" + "log" + "os" + "strings" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + ldap "gopkg.in/ldap.v2" + + util "git.metaunix.net/metaunix.net/muldap/lib/util" +) + +func init() { + // define group delete subcommand flags + groupDeleteMemberCmd.Flags().StringP("base_ou", "o", "", "LDAP OU to search for the group entry under") + groupDeleteMemberCmd.Flags().StringP("id_attribute", "a", "cn", "LDAP DN attribute for groups") + groupDeleteMemberCmd.Flags().StringVarP(&flagGroupName, "group_name", "n", "", "Name for the group") + groupDeleteMemberCmd.Flags().StringVarP(&flagGroupType, "group_type", "t", "unix", "Type of the group") + groupDeleteMemberCmd.Flags().StringVarP(&flagGroupMembers, "group_members", "m", "", "Members to Delete from the group (comma-separated list)") + // bind config file values to group delete flags + viper.BindPFlag("group.base_ou", groupDeleteMemberCmd.Flags().Lookup("base_ou")) + viper.BindPFlag("group.id_attr", groupDeleteMemberCmd.Flags().Lookup("id_attribute")) +} + +// define group delete subcommand +var groupDeleteMemberCmd = &cobra.Command{ + Use: "deleteMember", + Short: "Delete a member to an LDAP group", + Long: `Deletes an LDAP user as a member of an LDAP group.`, + Run: func(cmd *cobra.Command, args []string) { + // check the type given + if !util.ContainsString(validTypes, flagGroupType) { + log.Fatal(fmt.Errorf("%s is not a valid group type; valid types are: %v", flagGroupType, validTypes)) + os.Exit(1) + } + + // check if users were supplied + if flagGroupMembers == "" { + log.Fatal(fmt.Errorf("you didn't supply any members to delete to the group")) + os.Exit(1) + } + + // create new LDAP connection + l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", viper.GetString("host"), viper.GetInt("port"))) + if err != nil { + log.Fatal(err) + } + defer l.Close() + + // bind as the admin dn + err = l.Bind(viper.GetString("bind_dn"), viper.GetString("bind_pw")) + if err != nil { + log.Fatal(err) + } + + // set up group attributes + groupDn := fmt.Sprintf("%s=%s,%s", viper.GetString("group.id_attr"), flagGroupName, viper.GetString("group.base_ou")) + // create new LDAP modify request + groupMod := ldap.NewModifyRequest(groupDn) + + // split list of group members + groupMembers := strings.Split(flagGroupMembers, ",") + + // delete attributes based on group type + if flagGroupType == "unix" { + // delete new member attribute + groupMod.Delete("memberUid", groupMembers) + } else if flagGroupType == "app" { + // loop through app group members to create their full DNs + for i, member := range groupMembers { + groupMembers[i] = fmt.Sprintf("%s=%s,%s", viper.GetString("user.uid_attr"), member, viper.GetString("user.base_ou")) + } + // delete member attribute + groupMod.Delete("member", groupMembers) + } + + // perform the delete operation + err = l.Modify(groupMod) + if err != nil { + log.Fatal(err) + } + + // create and send a modify request for each user to update modification times for replication + if flagGroupMembers != "" && flagGroupType == "app" { + groupMembers := strings.Split(flagGroupMembers, ",") + for _, member := range groupMembers { + userMod := ldap.NewModifyRequest(fmt.Sprintf("%s=%s,%s", viper.GetString("user.uid_attr"), member, viper.GetString("user.base_ou"))) + userMod.Replace(viper.GetString("user.uid_attr"), []string{member}) + err = l.Modify(userMod) + if err != nil { + log.Fatal(err) + } + } + } + }, +} diff --git a/cmd/group/group.go b/cmd/group/group.go index 27a2f3d..115cf21 100644 --- a/cmd/group/group.go +++ b/cmd/group/group.go @@ -10,23 +10,23 @@ var ( // group subcommand arguments flagGroupName string flagGroupType string - flagGroupIdNumber int + flagGroupIDNumber int flagGroupMembers string - validTypes []string = []string{"app", "unix"} + validTypes = []string{"app", "unix"} ) func init() { // register group subcommands - GroupCmd.AddCommand(groupAddCmd, groupDeleteCmd, groupAddMemberCmd) + GroupCmd.AddCommand(groupAddCmd, groupDeleteCmd, groupAddMemberCmd, groupDeleteMemberCmd) } -// define group command +// GroupCmd - define group command var GroupCmd = &cobra.Command{ Use: "group", Short: "Manage LDAP group resources", Long: `Perform various LDAP operations on group resources.`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println("Metaunix.net LDAP tool, group command. Available subcommands are: add, delete, addMember") + fmt.Println("Metaunix.net LDAP tool, group command. Available subcommands are: add, delete, addMember, deleteMember") }, }