github.com/tommi2day/pwcli@v0.0.0-20240317203041-4d1177a5ab91/cmd/ldap.go (about)

     1  package cmd
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"strings"
     7  
     8  	ldap "github.com/go-ldap/ldap/v3"
     9  
    10  	"github.com/manifoldco/promptui"
    11  	log "github.com/sirupsen/logrus"
    12  	"github.com/spf13/cobra"
    13  	"github.com/spf13/viper"
    14  	"github.com/tommi2day/gomodules/common"
    15  	"github.com/tommi2day/gomodules/ldaplib"
    16  	"github.com/tommi2day/gomodules/pwlib"
    17  )
    18  
    19  var ldapServer = ""
    20  var ldapBindDN = ""
    21  var ldapBindPassword = ""
    22  var ldapBaseDN = ""
    23  var targetDN = ""
    24  var ldapPort = 0
    25  var ldapInsecure = false
    26  var ldapTLS = false
    27  var ldapTimeout = 20
    28  var ldapGroupBase = ""
    29  var ldapTargetUser = ""
    30  var inputReader = os.Stdin
    31  
    32  const ldapPublicKeyObjectClass = "ldapPublicKey"
    33  const ldapSSHAttr = "sshPublicKey"
    34  
    35  // nolint gosec
    36  const ldapPasswordProfile = "8 1 1 1 0 0"
    37  
    38  // var ldapUserContext = "ou=users"
    39  
    40  var ldapCmd = &cobra.Command{
    41  	Use:   "ldap",
    42  	Short: "commands related to ldap",
    43  }
    44  
    45  // ldapPassCmd represents the new command
    46  var ldapPassCmd = &cobra.Command{
    47  	Use:     "setpass",
    48  	Aliases: []string{"change-password"},
    49  	Short:   "change LDAP Password for given User per DN",
    50  	Long: `set new ldap password by --new-password or Env LDAP_NEW_PASSWORD for the actual bind DN or as admin bind for a target DN.
    51  if no new password given some systems will generate a password`,
    52  	RunE:         setLdapPass,
    53  	SilenceUsage: true,
    54  }
    55  
    56  // ldapPassCmd represents the new command
    57  var ldapSSHCmd = &cobra.Command{
    58  	Use:          "setssh",
    59  	Aliases:      []string{"change-sshpubkey"},
    60  	Short:        "Set public SSH Key to LDAP DN",
    61  	Long:         `set new ssh public key(attribute sshPublicKey) for a given User per DN, the key must be in a file given by --sshpubkeyfile or default id_rsa.pub.`,
    62  	RunE:         setSSHKey,
    63  	SilenceUsage: true,
    64  }
    65  
    66  // ldapShowCmd represents the new command
    67  var ldapShowCmd = &cobra.Command{
    68  	Use:     "show",
    69  	Aliases: []string{"show-attributes", "attributes"},
    70  	Short:   "Show attributes of LDAP DN",
    71  	Long: `This command shows the attributes off the own User(Bind User) or
    72  you may lookup a User cn and show the attributes of the first entry returned.`,
    73  	RunE:         showAttributes,
    74  	SilenceUsage: true,
    75  }
    76  
    77  // ldapGroupCmd represents the new command
    78  var ldapGroupCmd = &cobra.Command{
    79  	Use:     "groups",
    80  	Aliases: []string{"show-groups", "group-membership"},
    81  	Short:   "Show the group memberships of the given DN",
    82  	Long: `This command shows the group membership of  own User(Bind User) or
    83  you may lookup a User cn and if found show the groups of the first entry returned`,
    84  	RunE:         showGroups,
    85  	SilenceUsage: true,
    86  }
    87  var hideFlags = func(command *cobra.Command, strings []string) {
    88  	// Hide flag for this command
    89  	_ = command.Flags().MarkHidden("app")
    90  	_ = command.Flags().MarkHidden("keydir")
    91  	_ = command.Flags().MarkHidden("datadir")
    92  	_ = command.Flags().MarkHidden("config")
    93  	_ = command.Flags().MarkHidden("method")
    94  	// Call parent help func
    95  	command.Parent().HelpFunc()(command, strings)
    96  }
    97  
    98  func showGroups(_ *cobra.Command, _ []string) error {
    99  	log.Debugf("ldap groups called")
   100  	lc, err := ldapLogin()
   101  	if err != nil {
   102  		log.Warnf("ldap login returned error %v", err)
   103  		return err
   104  	}
   105  
   106  	// validate parameter
   107  	if ldapGroupBase == "" {
   108  		ldapGroupBase = ldapBaseDN
   109  	}
   110  
   111  	// lookup target user if given
   112  	udn := ""
   113  	if ldapTargetUser != "" {
   114  		udn, err = lookupTargetUser(lc, ldapTargetUser)
   115  		if err != nil {
   116  			log.Errorf("%v", err)
   117  			return err
   118  		}
   119  		if udn != "" {
   120  			targetDN = udn
   121  		}
   122  	}
   123  	log.Debugf("targetDN:%s", targetDN)
   124  	// search for targetDN entry
   125  	filter := fmt.Sprintf("(|(&(objectclass=groupOfUniqueNames)(uniqueMember=%s))(&(objectclass=groupOfNames)(member=%s)))", targetDN, targetDN)
   126  	log.Debugf("ldap search for groups with filter %s", filter)
   127  	entries, err := lc.Search(ldapGroupBase, filter, []string{"DN"}, ldap.ScopeWholeSubtree, ldap.DerefInSearching)
   128  	if err != nil {
   129  		log.Errorf("search for %s returned error %v", targetDN, err)
   130  		return fmt.Errorf("search for %s returned error %v", targetDN, err)
   131  	}
   132  	if len(entries) == 0 {
   133  		log.Warnf("no groups for %s found", targetDN)
   134  		fmt.Printf("no groups for %s found", targetDN)
   135  		return nil
   136  	}
   137  	fmt.Printf("DN '%s' is member of the following groups:\n", targetDN)
   138  	for _, e := range entries {
   139  		log.Infof("Group: %s", e.DN)
   140  		fmt.Printf("Group: %s\n", e.DN)
   141  	}
   142  	return nil
   143  }
   144  
   145  func showAttributes(cmd *cobra.Command, _ []string) error {
   146  	log.Debugf("ldap show called")
   147  	lc, err := ldapLogin()
   148  	if err != nil {
   149  		log.Warnf("ldap login returned error %v", err)
   150  		return err
   151  	}
   152  
   153  	// validate parameter
   154  	attributes, _ := cmd.Flags().GetString("attributes")
   155  	if attributes == "" {
   156  		attributes = "*"
   157  	}
   158  
   159  	// lookup target user if given
   160  	udn := ""
   161  	if ldapTargetUser != "" {
   162  		udn, err = lookupTargetUser(lc, ldapTargetUser)
   163  		if err != nil {
   164  			log.Errorf("%v", err)
   165  			return err
   166  		}
   167  		if udn != "" {
   168  			targetDN = udn
   169  		}
   170  	}
   171  	log.Debugf("targetDN:%s", targetDN)
   172  
   173  	// search for targetDN entry
   174  	log.Debugf("ldap search for %s", targetDN)
   175  	e, err := lc.RetrieveEntry(targetDN, "", attributes)
   176  	if err != nil {
   177  		log.Errorf("search for %s returned error %v", targetDN, err)
   178  		return fmt.Errorf("search for %s returned error %v", targetDN, err)
   179  	}
   180  	if e == nil {
   181  		log.Errorf("ldap search for %s returned no entry", targetDN)
   182  		return fmt.Errorf("ldap search for %s returned no entry", targetDN)
   183  	}
   184  	fmt.Printf("DN '%s' has following attributes:\n", targetDN)
   185  	values := e.Attributes
   186  	for _, v := range values {
   187  		name := v.Name
   188  		for _, val := range v.Values {
   189  			log.Infof("%s: %s", name, val)
   190  			fmt.Printf("%s: %s\n", name, val)
   191  		}
   192  	}
   193  	return nil
   194  }
   195  
   196  func promptPassword(label string) (pw string, err error) {
   197  	prompt := promptui.Prompt{
   198  		Label: label,
   199  		Mask:  '*',
   200  		Stdin: inputReader,
   201  	}
   202  
   203  	result, err := prompt.Run()
   204  	if err != nil {
   205  		return
   206  	}
   207  	pw = result
   208  	return
   209  }
   210  
   211  func enterNewPassword() (pw string, err error) {
   212  	pw, err = promptPassword("Enter NEW password")
   213  	if err != nil {
   214  		err = fmt.Errorf("error reading password: %v", err)
   215  		return
   216  	}
   217  	log.Debugf("PW1: '%s'", pw)
   218  	pw2 := ""
   219  	if !unitTestFlag {
   220  		pw2, err = promptPassword("Repeat NEW password")
   221  	} else {
   222  		// cannot use second promptui in unit tests
   223  		pw2 = pw
   224  	}
   225  	log.Debugf("PW2: '%s'", pw)
   226  	if err != nil {
   227  		err = fmt.Errorf("error reading password: %v", err)
   228  		return
   229  	}
   230  	if pw != pw2 {
   231  		err = fmt.Errorf("passwords do not match")
   232  	}
   233  	return
   234  }
   235  
   236  func generatePassword(p string) (pw string, err error) {
   237  	log.Debugf("generated Password")
   238  	profile, e := setPasswordProfile(p)
   239  	if e != nil {
   240  		return "", e
   241  	}
   242  	pw, err = pwlib.GenPassword(profile.Length, profile.Upper, profile.Lower, profile.Digits, profile.Special, profile.Firstchar)
   243  	if err != nil {
   244  		log.Errorf("password generation returned error %v", err)
   245  		return
   246  	}
   247  	log.Debugf("generated Password: %s", pw)
   248  	return
   249  }
   250  
   251  func getNewPassword(cmd *cobra.Command) (newPassword string, err error) {
   252  	generate, _ := cmd.Flags().GetBool("generate")
   253  	if generate {
   254  		p, _ := cmd.Flags().GetString("profile")
   255  		newPassword, err = generatePassword(p)
   256  		if err != nil {
   257  			return
   258  		}
   259  		log.Infof("generated Password: %s", newPassword)
   260  		fmt.Printf("generated Password: %s\n", newPassword)
   261  	} else {
   262  		newPassword, _ = cmd.Flags().GetString("new-password")
   263  		if newPassword == "" {
   264  			newPassword = os.Getenv("LDAP_NEW_PASSWORD")
   265  			if newPassword != "" {
   266  				log.Debugf("use new password from env: %s", newPassword)
   267  			}
   268  		}
   269  		if newPassword == "" {
   270  			fmt.Printf("Change password for %s\n", targetDN)
   271  			newPassword, err = enterNewPassword()
   272  			if err != nil {
   273  				return
   274  			}
   275  		}
   276  	}
   277  	return
   278  }
   279  func setLdapPass(cmd *cobra.Command, _ []string) error {
   280  	log.Debugf("ldap password called")
   281  	// login to server
   282  	lc, err := ldapLogin()
   283  	if err != nil {
   284  		log.Errorf("ldap login returned error %v", err)
   285  		return err
   286  	}
   287  	// lookup target user if given
   288  	udn := ""
   289  	if ldapTargetUser != "" {
   290  		udn, err = lookupTargetUser(lc, ldapTargetUser)
   291  		if err != nil {
   292  			log.Errorf("%v", err)
   293  			return err
   294  		}
   295  		if udn != "" {
   296  			targetDN = udn
   297  		}
   298  	}
   299  	log.Debugf("targetDN: %s", targetDN)
   300  
   301  	// validate parameter
   302  	newPassword := ""
   303  	newPassword, err = getNewPassword(cmd)
   304  	if err != nil {
   305  		return err
   306  	}
   307  	if newPassword == "" {
   308  		// err = fmt.Errorf("no new password given, use --new_password or Env LDAP_NEW_PASSWORD")
   309  		// return err
   310  		log.Infof("even no new password given, it will be generated in some systems ldap system such as openldap")
   311  	}
   312  
   313  	//  for self write old password must be given und targetDN empty. for admin write targetDN must be given and old password empty
   314  	oldPass := ""
   315  	dn := targetDN
   316  	if targetDN == ldapBindDN {
   317  		oldPass = ldapBindPassword
   318  		dn = ""
   319  		log.Debugf("change password for myself")
   320  	}
   321  	// change password
   322  	genPass := ""
   323  	genPass, err = lc.SetPassword(dn, oldPass, newPassword)
   324  	if err != nil {
   325  		log.Errorf("ldap password change for %s returned error %v", targetDN, err)
   326  		return fmt.Errorf("ldap password change for %s returned error %v", targetDN, err)
   327  	}
   328  	log.Infof("Password for %s changed", targetDN)
   329  	if genPass == "" {
   330  		genPass = newPassword
   331  	} else {
   332  		log.Infof("generated Password: %s", genPass)
   333  		fmt.Printf("generated Password: %s\n", genPass)
   334  	}
   335  	l := lc.Conn
   336  	_ = l.Close()
   337  
   338  	// reconnect with new password to verify
   339  	log.Debugf("reconnect with new password to verify")
   340  	err = lc.Connect(targetDN, genPass)
   341  	if err != nil {
   342  		log.Errorf("ldap test bind to %s with new pass returned error %v", targetDN, err)
   343  		return fmt.Errorf("ldap test bind to %s with new pass returned error %v", targetDN, err)
   344  	}
   345  	l = lc.Conn
   346  	if l != nil {
   347  		_ = l.Close()
   348  	}
   349  	log.Infof("SUCCESS: Password for %s changed and tested", targetDN)
   350  	fmt.Printf("Password for %s changed and tested\n", targetDN)
   351  	return nil
   352  }
   353  
   354  func setSSHKey(cmd *cobra.Command, _ []string) error {
   355  	log.Debugf("ldap ssh key called")
   356  	lc, err := ldapLogin()
   357  	if err != nil {
   358  		log.Warnf("ldap login returned error %v", err)
   359  		return err
   360  	}
   361  
   362  	// lookup target user if given
   363  	udn := ""
   364  	if ldapTargetUser != "" {
   365  		udn, err = lookupTargetUser(lc, ldapTargetUser)
   366  		if err != nil {
   367  			log.Errorf("%v", err)
   368  			return err
   369  		}
   370  		if udn != "" {
   371  			targetDN = udn
   372  		}
   373  	}
   374  	log.Debugf("targetDN: %s", targetDN)
   375  	// validate parameter
   376  	sshPubKeyFile, _ := cmd.Flags().GetString("sshpubkeyfile")
   377  	if sshPubKeyFile == "" {
   378  		log.Warnf("sshpubkeyfile not given")
   379  		return fmt.Errorf("sshpubkeyfile not given")
   380  	}
   381  	if !common.IsFile(sshPubKeyFile) {
   382  		log.Warnf("sshpubkeyfile %s not found", sshPubKeyFile)
   383  		return fmt.Errorf("sshpubkeyfile %s not found", sshPubKeyFile)
   384  	}
   385  
   386  	// read ssh key
   387  	pubKey := ""
   388  	pubKey, err = common.ReadFileToString(sshPubKeyFile)
   389  	if err != nil {
   390  		log.Warnf("sshpubkeyfile %s not readable", sshPubKeyFile)
   391  		return fmt.Errorf("sshpubkeyfile %s not readable", sshPubKeyFile)
   392  	}
   393  	log.Debugf("got ssh key from file %s", sshPubKeyFile)
   394  	// search for targetDN entry
   395  	log.Debugf("ldap exact search for %s", targetDN)
   396  	l := lc.Conn
   397  	e, err := lc.RetrieveEntry(targetDN, "", "")
   398  	if err != nil {
   399  		log.Errorf("search for %s returned error %v", targetDN, err)
   400  		return fmt.Errorf("search for %s returned error %v", targetDN, err)
   401  	}
   402  	if e == nil {
   403  		log.Errorf("ldap search for %s returned no entry", targetDN)
   404  		return fmt.Errorf("ldap search for %s returned no entry", targetDN)
   405  	}
   406  	log.Debugf("%s: look for objectclass %s ", targetDN, ldapSSHAttr)
   407  	// check if attribute is assigned
   408  	if !ldaplib.HasObjectClass(e, ldapPublicKeyObjectClass) {
   409  		log.Errorf("objectclass %s not found for %s", ldapPublicKeyObjectClass, targetDN)
   410  		return fmt.Errorf("objectclass %s not found for %s", ldapPublicKeyObjectClass, targetDN)
   411  	}
   412  
   413  	// check if attribute is already assigned or should added
   414  	action := "replace"
   415  	if !ldaplib.HasAttribute(e, ldapSSHAttr) {
   416  		action = "add"
   417  		log.Infof("attribute %s not found for %s, will be added", ldapSSHAttr, targetDN)
   418  	}
   419  
   420  	// change or add ssh key
   421  	log.Debugf("change ssh key for %s", targetDN)
   422  	err = lc.ModifyAttribute(targetDN, action, ldapSSHAttr, []string{pubKey})
   423  	if err != nil {
   424  		log.Errorf("ldap ssh key change for %s returned error %v", targetDN, err)
   425  		return fmt.Errorf("ldap ssh key change for %s returned error %v", targetDN, err)
   426  	}
   427  	if err = verifySSHKey(lc, pubKey); err != nil {
   428  		log.Errorf("%v", err)
   429  		return err
   430  	}
   431  	log.Infof("SUCCESS: SSH Key for %s changed", targetDN)
   432  	fmt.Printf("SSH Key for %s changed\n", targetDN)
   433  	_ = l.Close()
   434  	return nil
   435  }
   436  
   437  func verifySSHKey(lc *ldaplib.LdapConfigType, pubKey string) (err error) {
   438  	var e *ldap.Entry
   439  	// check if ssh key was changed
   440  	log.Debugf("search for %s attribute %s to verify ssh key", targetDN, ldapSSHAttr)
   441  	e, err = lc.RetrieveEntry(targetDN, "", ldapSSHAttr)
   442  	if err != nil {
   443  		log.Errorf("validate search for %s returned error %v", targetDN, err)
   444  		return fmt.Errorf("validate search for %s returned error %v", targetDN, err)
   445  	}
   446  	actSSH := e.GetAttributeValue(ldapSSHAttr)
   447  	if actSSH != pubKey {
   448  		log.Errorf("ldap ssh key change for %s not successful, new value not as expected", targetDN)
   449  		return fmt.Errorf("ldap ssh key change for %s not successful, new value not as expected", targetDN)
   450  	}
   451  	return
   452  }
   453  func lookupTargetUser(lc *ldaplib.LdapConfigType, user string) (dn string, err error) {
   454  	log.Debugf("lookup user %s", user)
   455  	if user == "" {
   456  		return
   457  	}
   458  	if ldapBaseDN == "" {
   459  		err = fmt.Errorf("no ldap base given")
   460  		return
   461  	}
   462  	filter := fmt.Sprintf("(|(cn=%s)(uid=%s))", user, user)
   463  	log.Debugf("search with filter %s from %s", user, ldapBaseDN)
   464  	entries, err := lc.Search(ldapBaseDN, filter, []string{"DN"}, ldap.ScopeWholeSubtree, ldap.DerefInSearching)
   465  	if err != nil {
   466  		err = fmt.Errorf("ldap search for user %s returned error %v", user, err)
   467  		return
   468  	}
   469  	l := len(entries)
   470  	if l == 0 {
   471  		err = fmt.Errorf("ldap search for user  %s returned no entry", user)
   472  		return
   473  	}
   474  	if l > 1 {
   475  		log.Debugf("search for user %s returned %d entries", user, l)
   476  		list := make([]string, l)
   477  		for i, e := range entries {
   478  			list[i] = e.DN
   479  		}
   480  		prompt := promptui.Select{
   481  			Label: "Select one of the following entries",
   482  			Items: list,
   483  		}
   484  
   485  		_, dn, err = prompt.Run()
   486  
   487  		if err != nil {
   488  			fmt.Printf("select entry failed %v\n", err)
   489  			return
   490  		}
   491  	} else {
   492  		dn = entries[0].DN
   493  	}
   494  	log.Debugf("use dn %s for user %s", dn, user)
   495  	return
   496  }
   497  
   498  func init() {
   499  	ldapCmd.PersistentFlags().StringVarP(&ldapServer, "ldap.host", "H", "", "Hostname of Ldap Server")
   500  	ldapCmd.PersistentFlags().IntVarP(&ldapPort, "ldap.port", "P", ldapPort, "ldap port to connect")
   501  	ldapCmd.PersistentFlags().StringVarP(&ldapBaseDN, "ldap.base", "b", "", "Ldap Base DN ")
   502  	ldapCmd.PersistentFlags().StringVarP(&targetDN, "ldap.targetdn", "T", "", "DN of target User for admin executed password change, empty for own entry (uses LDAP_BIND_DN)")
   503  	ldapCmd.PersistentFlags().StringVarP(&ldapTargetUser, "ldap.targetuser", "U", "", "uid to search for targetDN")
   504  	ldapCmd.PersistentFlags().StringVarP(&ldapBindDN, "ldap.binddn", "B", "", "DN of user for LDAP bind or use Env LDAP_BIND_DN")
   505  	ldapCmd.PersistentFlags().StringVarP(&ldapBindPassword, "ldap.bindpassword", "p", "", "password for LDAP Bind User or use Env LDAP_BIND_PASSWORD")
   506  	ldapCmd.PersistentFlags().BoolVar(&ldapTLS, "ldap.tls", false, "use secure ldap (ldaps)")
   507  	ldapCmd.PersistentFlags().BoolVarP(&ldapInsecure, "ldap.insecure", "I", false, "do not verify TLS")
   508  	ldapCmd.PersistentFlags().IntVarP(&ldapTimeout, "ldap.timeout", "t", ldapTimeout, "ldap timeout in sec")
   509  	// ldapCmd.SetHelpFunc(hideFlags)
   510  	ldapPassCmd.Flags().StringP("new-password", "n", "", "new_password to set or use Env LDAP_NEW_PASSWORD or be prompted")
   511  	ldapPassCmd.Flags().BoolP("generate", "g", false, "generate a new password (alternative to be prompted)")
   512  	ldapPassCmd.Flags().String("profile", ldapPasswordProfile, "set profile string as numbers of 'length Upper Lower Digits Special FirstcharFlag(0/1)'")
   513  	ldapPassCmd.MarkFlagsMutuallyExclusive("new-password", "generate")
   514  	ldapCmd.AddCommand(ldapPassCmd)
   515  
   516  	ldapSSHCmd.Flags().StringP("sshpubkeyfile", "f", "id_rsa.pub", "filename with ssh public key to upload")
   517  	ldapSSHCmd.SetHelpFunc(hideFlags)
   518  	ldapCmd.AddCommand(ldapSSHCmd)
   519  
   520  	ldapShowCmd.Flags().StringP("attributes", "A", "*", "comma separated list of attributes to show")
   521  	ldapShowCmd.SetHelpFunc(hideFlags)
   522  	ldapCmd.AddCommand(ldapShowCmd)
   523  
   524  	ldapGroupCmd.PersistentFlags().StringVarP(&ldapGroupBase, "ldap.groupbase", "G", "", "Base DN for group search")
   525  	ldapGroupCmd.SetHelpFunc(hideFlags)
   526  	ldapCmd.AddCommand(ldapGroupCmd)
   527  
   528  	RootCmd.AddCommand(ldapCmd)
   529  
   530  	if err := viper.BindPFlags(ldapCmd.PersistentFlags()); err != nil {
   531  		log.Fatal(err)
   532  	}
   533  }
   534  
   535  func initLdapConfig() {
   536  	if ldapServer == "" {
   537  		ldapServer = viper.GetString("ldap.host")
   538  	}
   539  	if ldapPort == 0 {
   540  		ldapPort = viper.GetInt("ldap.port")
   541  	}
   542  	if ldapBaseDN == "" {
   543  		ldapBaseDN = viper.GetString("ldap.base")
   544  	}
   545  	if ldapBindDN == "" {
   546  		ldapBindDN = viper.GetString("ldap.binddn")
   547  	}
   548  	if ldapBindPassword == "" {
   549  		ldapBindPassword = viper.GetString("ldap.bindpassword")
   550  	}
   551  	if ldapGroupBase == "" {
   552  		ldapGroupBase = viper.GetString("ldap.groupbase")
   553  	}
   554  
   555  	if targetDN == "" {
   556  		targetDN = ldapBindDN
   557  	}
   558  
   559  	if common.CmdFlagChanged(ldapCmd, "ldap.tls") {
   560  		viper.Set("ldap.tls", ldapTLS)
   561  	} else {
   562  		ldapTLS = viper.GetBool("ldap.tls")
   563  	}
   564  	if common.CmdFlagChanged(ldapCmd, "ldap.insecure") {
   565  		viper.Set("ldap.insecure", ldapInsecure)
   566  	} else {
   567  		ldapInsecure = viper.GetBool("ldap.insecure")
   568  	}
   569  	if common.CmdFlagChanged(ldapCmd, "ldap.timeout") {
   570  		viper.Set("ldap.timeout", ldapTimeout)
   571  	} else {
   572  		ldapTimeout = viper.GetInt("ldap.timeout")
   573  	}
   574  }
   575  func loadFromEnv() {
   576  	if ldapBindDN == "" {
   577  		ldapBindDN = os.Getenv("LDAP_BIND_DN")
   578  		if ldapBindDN != "" {
   579  			log.Debugf("use new LDAP_BIND_DN from env: %s", ldapBindDN)
   580  		}
   581  	}
   582  	if ldapBindPassword == "" {
   583  		ldapBindPassword = os.Getenv("LDAP_BIND_PASSWORD")
   584  		if ldapBindPassword != "" {
   585  			log.Debugf("use LDAP_BIND_PASSWORD from env")
   586  		}
   587  	}
   588  }
   589  func ldapLogin() (lc *ldaplib.LdapConfigType, err error) {
   590  	initLdapConfig()
   591  	loadFromEnv()
   592  	if ldapBindDN == "" {
   593  		err = fmt.Errorf("no LDAP Bind DN given, use --ldap.binddn or Env LDAP_BIND_DN")
   594  		return
   595  	}
   596  	if ldapBaseDN == "" {
   597  		p := strings.Split(ldapBindDN, ",")
   598  		l := len(p)
   599  		if l > 2 {
   600  			ldapBaseDN = strings.Join(p[l-2:], ",")
   601  			log.Debugf("use baseDN from bindDN: %s", ldapBaseDN)
   602  		}
   603  	}
   604  
   605  	// query password if not given
   606  	if ldapBindPassword == "" {
   607  		pw := ""
   608  		pw, err = promptPassword("Enter Bind password")
   609  		if err != nil {
   610  			err = fmt.Errorf("error reading password: %v", err)
   611  			return
   612  		}
   613  		ldapBindPassword = pw
   614  	}
   615  	if ldapBindPassword == "" {
   616  		err = fmt.Errorf("no LDAP Bind Password given, use --ldap.bindpass or Env LDAP_BIND_PASSWORD")
   617  		return
   618  	}
   619  
   620  	log.Debugf("Try to connect to Ldap Server %s, Port %d, TLS %v, Insecure %v", ldapServer, ldapPort, ldapTLS, ldapInsecure)
   621  	lc = ldaplib.NewConfig(ldapServer, ldapPort, ldapTLS, ldapInsecure, ldapBaseDN, ldapTimeout)
   622  	err = lc.Connect(ldapBindDN, ldapBindPassword)
   623  	if err != nil {
   624  		err = fmt.Errorf("ldap bind to %s returned error %v", ldapBindDN, err)
   625  		return
   626  	}
   627  	if err == nil && lc.Conn != nil {
   628  		log.Debugf("Ldap Connected")
   629  	}
   630  	return
   631  }