github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/idp-ldap-accesskey-list.go (about)

     1  // Copyright (c) 2015-2023 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package cmd
    19  
    20  import (
    21  	"errors"
    22  	"strings"
    23  
    24  	"github.com/charmbracelet/lipgloss"
    25  	"github.com/minio/cli"
    26  	json "github.com/minio/colorjson"
    27  	"github.com/minio/madmin-go/v3"
    28  	"github.com/minio/mc/pkg/probe"
    29  )
    30  
    31  var idpLdapAccesskeyListFlags = []cli.Flag{
    32  	cli.BoolFlag{
    33  		Name:  "users-only",
    34  		Usage: "only list user DNs",
    35  	},
    36  	cli.BoolFlag{
    37  		Name:  "temp-only",
    38  		Usage: "only list temporary access keys",
    39  	},
    40  	cli.BoolFlag{
    41  		Name:  "svcacc-only",
    42  		Usage: "only list service account access keys",
    43  	},
    44  }
    45  
    46  var idpLdapAccesskeyListCmd = cli.Command{
    47  	Name:         "list",
    48  	ShortName:    "ls",
    49  	Usage:        "list access key pairs for LDAP",
    50  	Action:       mainIDPLdapAccesskeyList,
    51  	Before:       setGlobalsFromContext,
    52  	Flags:        append(idpLdapAccesskeyListFlags, globalFlags...),
    53  	OnUsageError: onUsageError,
    54  	CustomHelpTemplate: `NAME:
    55    {{.HelpName}} - {{.Usage}}
    56  
    57  USAGE:
    58    {{.HelpName}} [FLAGS] TARGET [DN...]
    59  
    60  FLAGS:
    61    {{range .VisibleFlags}}{{.}}
    62    {{end}}
    63  EXAMPLES:
    64    1. Get list of all users and associated access keys in local server (if admin)
    65   	 {{.Prompt}} {{.HelpName}} local/
    66  
    67    2. Get list of users in local server (if admin)
    68   	 {{.Prompt}} {{.HelpName}} local/ --users-only
    69  
    70    3. Get list of all users and associated temporary access keys in play server (if admin)
    71  	 {{.Prompt}} {{.HelpName}} play/ --temp-only
    72  
    73    4. Get list of access keys associated with user 'bobfisher'
    74    	 {{.Prompt}} {{.HelpName}} play/ uid=bobfisher,dc=min,dc=io
    75  
    76    5. Get list of access keys associated with user 'bobfisher' (alt)
    77  	 {{.Prompt}} {{.HelpName}} play/ bobfisher
    78  
    79    6. Get list of access keys associated with users 'bobfisher' and 'cody3'
    80    	 {{.Prompt}} {{.HelpName}} play/ uid=bobfisher,dc=min,dc=io uid=cody3,dc=min,dc=io
    81  
    82    7. Get authenticated user and associated access keys in local server (if not admin)
    83  	 {{.Prompt}} {{.HelpName}} local/
    84  `,
    85  }
    86  
    87  type ldapUsersList struct {
    88  	Status          string                      `json:"status"`
    89  	DN              string                      `json:"dn"`
    90  	STSKeys         []madmin.ServiceAccountInfo `json:"stsKeys"`
    91  	ServiceAccounts []madmin.ServiceAccountInfo `json:"svcaccs"`
    92  }
    93  
    94  func (m ldapUsersList) String() string {
    95  	labelStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#04B575"))
    96  	o := strings.Builder{}
    97  
    98  	o.WriteString(iFmt(0, "%s\n", labelStyle.Render("DN "+m.DN)))
    99  	if len(m.STSKeys) > 0 {
   100  		o.WriteString(iFmt(2, "%s\n", labelStyle.Render("STS Access Keys:")))
   101  		for _, k := range m.STSKeys {
   102  			o.WriteString(iFmt(4, "%s\n", k.AccessKey))
   103  		}
   104  	}
   105  	if len(m.ServiceAccounts) > 0 {
   106  		o.WriteString(iFmt(2, "%s\n", labelStyle.Render("Service Account Access Keys:")))
   107  		for _, k := range m.ServiceAccounts {
   108  			o.WriteString(iFmt(4, "%s\n", k.AccessKey))
   109  		}
   110  	}
   111  	o.WriteString("\n")
   112  
   113  	return o.String()
   114  }
   115  
   116  func (m ldapUsersList) JSON() string {
   117  	jsonMessageBytes, e := json.MarshalIndent(m, "", " ")
   118  	fatalIf(probe.NewError(e), "Unable to marshal into JSON.")
   119  
   120  	return string(jsonMessageBytes)
   121  }
   122  
   123  func mainIDPLdapAccesskeyList(ctx *cli.Context) error {
   124  	if len(ctx.Args()) == 0 {
   125  		showCommandHelpAndExit(ctx, 1) // last argument is exit code
   126  	}
   127  
   128  	usersOnly := ctx.Bool("users-only")
   129  	tempOnly := ctx.Bool("sts-only")
   130  	permanentOnly := ctx.Bool("svcacc-only")
   131  	listType := ""
   132  
   133  	if (usersOnly && permanentOnly) || (usersOnly && tempOnly) || (permanentOnly && tempOnly) {
   134  		e := errors.New("only one of --users-only, --temp-only, or --permanent-only can be specified")
   135  		fatalIf(probe.NewError(e), "Invalid flags.")
   136  	}
   137  	if tempOnly {
   138  		listType = "sts-only"
   139  	} else if permanentOnly {
   140  		listType = "svcacc-only"
   141  	}
   142  
   143  	args := ctx.Args()
   144  	aliasedURL := args.Get(0)
   145  	userArg := args.Tail()
   146  
   147  	// Create a new MinIO Admin Client
   148  	client, err := newAdminClient(aliasedURL)
   149  	fatalIf(err, "Unable to initialize admin connection.")
   150  
   151  	var e error
   152  	var users map[string]madmin.UserInfo
   153  
   154  	// If no users given, attempt to list all users
   155  	if len(userArg) == 0 {
   156  		users, e = client.ListUsers(globalContext)
   157  	} else {
   158  		users = make(map[string]madmin.UserInfo)
   159  		for _, user := range userArg {
   160  			users[user] = madmin.UserInfo{}
   161  		}
   162  	}
   163  	if e != nil {
   164  		if e.Error() == "Access Denied." {
   165  			// If user does not have ListUsers permission, only get current user's access keys
   166  			users = make(map[string]madmin.UserInfo)
   167  			users[""] = madmin.UserInfo{}
   168  		} else {
   169  			fatalIf(probe.NewError(e), "Unable to retrieve users.")
   170  		}
   171  	}
   172  
   173  	for dn := range users {
   174  		// if dn is blank, it means we are listing the current user's access keys
   175  		if dn == "" {
   176  			name, e := client.AccountInfo(globalContext, madmin.AccountOpts{})
   177  			fatalIf(probe.NewError(e), "Unable to retrieve account name.")
   178  			dn = name.AccountName
   179  		}
   180  
   181  		m := ldapUsersList{
   182  			Status: "success",
   183  			DN:     dn,
   184  		}
   185  
   186  		// Get access keys if not listing users only
   187  		if !usersOnly {
   188  			accessKeys, e := client.ListAccessKeysLDAP(globalContext, dn, listType)
   189  			if e != nil {
   190  				errorIf(probe.NewError(e), "Unable to retrieve access keys for user '"+dn+"'.")
   191  				continue
   192  			}
   193  
   194  			m.STSKeys = accessKeys.STSKeys
   195  			m.ServiceAccounts = accessKeys.ServiceAccounts
   196  		}
   197  		printMsg(m)
   198  	}
   199  	return nil
   200  }