code: func NewCSV(path string) (*PasswordAuthenticator, error) {
  	file, err := os.Open(path)
  	if err != nil {
  		return nil, err
  	}
  	defer file.Close()
  
  	recordNum := 0
  	users := make(map[string]*userPasswordInfo)
  	reader := csv.NewReader(file)
  	reader.FieldsPerRecord = -1
  	for {
  		record, err := reader.Read()
  		if err == io.EOF {
  			break
  		}
  		if err != nil {
  			return nil, err
  		}
  		if len(record) < 3 {
  			return nil, fmt.Errorf("password file '%s' must have at least 3 columns (password, user name, user uid), found %d", path, len(record))
  		}
  		obj := &userPasswordInfo{
  			info:     &user.DefaultInfo{Name: record[1], UID: record[2]},
  			password: record[0],
  		}
  		if len(record) >= 4 {
  			obj.info.Groups = strings.Split(record[3], ",")
  		}
  		recordNum++
  		if _, exist := users[obj.info.Name]; exist {
  			klog.Warningf("duplicate username '%s' has been found in password file '%s', record number '%d'", obj.info.Name, path, recordNum)
  		}
  		users[obj.info.Name] = obj
  	}
  
  	return &PasswordAuthenticator{users}, nil
  }
docs: // NewCSV returns a PasswordAuthenticator, populated from a CSV file.
  // The CSV file must contain records in the format "password,username,useruid"