diff --git a/cmd/admin-accesskey-create.go b/cmd/admin-accesskey-create.go
new file mode 100644
index 0000000000..42629c841d
--- /dev/null
+++ b/cmd/admin-accesskey-create.go
@@ -0,0 +1,94 @@
+// Copyright (c) 2015-2024 MinIO, Inc.
+//
+// This file is part of MinIO Object Storage stack
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package cmd
+
+import (
+ "github.com/minio/cli"
+)
+
+var adminAccesskeyCreateFlags = []cli.Flag{
+ cli.StringFlag{
+ Name: "access-key",
+ Usage: "set an access key for the account",
+ },
+ cli.StringFlag{
+ Name: "secret-key",
+ Usage: "set a secret key for the account",
+ },
+ cli.StringFlag{
+ Name: "policy",
+ Usage: "path to a JSON policy file",
+ },
+ cli.StringFlag{
+ Name: "name",
+ Usage: "friendly name for the account",
+ },
+ cli.StringFlag{
+ Name: "description",
+ Usage: "description for the account",
+ },
+ cli.StringFlag{
+ Name: "expiry-duration",
+ Usage: "duration before the access key expires",
+ },
+ cli.StringFlag{
+ Name: "expiry",
+ Usage: "expiry date for the access key",
+ },
+}
+
+var adminAccesskeyCreateCmd = cli.Command{
+ Name: "create",
+ Usage: "create access key pairs for users",
+ Action: mainAdminAccesskeyCreate,
+ Before: setGlobalsFromContext,
+ Flags: append(adminAccesskeyCreateFlags, globalFlags...),
+ OnUsageError: onUsageError,
+ CustomHelpTemplate: `NAME:
+ {{.HelpName}} - {{.Usage}}
+
+USAGE:
+ {{.HelpName}} [FLAGS] [TARGET]
+
+FLAGS:
+ {{range .VisibleFlags}}{{.}}
+ {{end}}
+EXAMPLES:
+ 1. Create a new access key pair with the same policy as the authenticated user
+ {{.Prompt}} {{.HelpName}} myminio/
+
+ 2. Create a new access key pair with custom access key and secret key
+ {{.Prompt}} {{.HelpName}} myminio/ --access-key myaccesskey --secret-key mysecretkey
+
+ 3. Create a new access key pair for user 'tester' that expires in 1 day
+ {{.Prompt}} {{.HelpName}} myminio/ tester --expiry-duration 24h
+
+ 4. Create a new access key pair for authenticated user that expires on 2025-01-01
+ {{.Prompt}} {{.HelpName}} --expiry 2025-01-01
+
+ 5. Create a new access key pair for user 'tester' with a custom policy
+ {{.Prompt}} {{.HelpName}} myminio/ tester --policy /path/to/policy.json
+
+ 6. Create a new access key pair for user 'tester' with a custom name and description
+ {{.Prompt}} {{.HelpName}} myminio/ tester --name "Tester's Access Key" --description "Access key for tester"
+`,
+}
+
+func mainAdminAccesskeyCreate(ctx *cli.Context) error {
+ return commonAccesskeyCreate(ctx, false)
+}
diff --git a/cmd/admin-accesskey-disable.go b/cmd/admin-accesskey-disable.go
new file mode 100644
index 0000000000..715f09e827
--- /dev/null
+++ b/cmd/admin-accesskey-disable.go
@@ -0,0 +1,48 @@
+// Copyright (c) 2015-2024 MinIO, Inc.
+//
+// This file is part of MinIO Object Storage stack
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package cmd
+
+import (
+ "github.com/minio/cli"
+)
+
+var adminAccesskeyDisableCmd = cli.Command{
+ Name: "disable",
+ Usage: "disable an access key",
+ Action: mainAdminAccesskeyDisable,
+ Before: setGlobalsFromContext,
+ Flags: globalFlags,
+ OnUsageError: onUsageError,
+ CustomHelpTemplate: `NAME:
+ {{.HelpName}} - {{.Usage}}
+
+USAGE:
+ {{.HelpName}} [FLAGS] [TARGET]
+
+FLAGS:
+ {{range .VisibleFlags}}{{.}}
+ {{end}}
+EXAMPLES:
+ 1. Disable access key
+ {{.Prompt}} {{.HelpName}} myminio myaccesskey
+`,
+}
+
+func mainAdminAccesskeyDisable(ctx *cli.Context) error {
+ return enableDisableAccesskey(ctx, false)
+}
diff --git a/cmd/admin-accesskey-edit.go b/cmd/admin-accesskey-edit.go
new file mode 100644
index 0000000000..e36df3c186
--- /dev/null
+++ b/cmd/admin-accesskey-edit.go
@@ -0,0 +1,77 @@
+// Copyright (c) 2015-2024 MinIO, Inc.
+//
+// This file is part of MinIO Object Storage stack
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package cmd
+
+import (
+ "github.com/minio/cli"
+)
+
+var adminAccesskeyEditFlags = []cli.Flag{
+ cli.StringFlag{
+ Name: "secret-key",
+ Usage: "set a secret key for the account",
+ },
+ cli.StringFlag{
+ Name: "policy",
+ Usage: "path to a JSON policy file",
+ },
+ cli.StringFlag{
+ Name: "name",
+ Usage: "friendly name for the account",
+ },
+ cli.StringFlag{
+ Name: "description",
+ Usage: "description for the account",
+ },
+ cli.StringFlag{
+ Name: "expiry-duration",
+ Usage: "duration before the access key expires",
+ },
+ cli.StringFlag{
+ Name: "expiry",
+ Usage: "expiry date for the access key",
+ },
+}
+
+var adminAccesskeyEditCmd = cli.Command{
+ Name: "edit",
+ Usage: "edit existing access keys",
+ Action: mainAdminAccesskeyEdit,
+ Before: setGlobalsFromContext,
+ Flags: append(adminAccesskeyEditFlags, globalFlags...),
+ OnUsageError: onUsageError,
+ CustomHelpTemplate: `NAME:
+ {{.HelpName}} - {{.Usage}}
+
+USAGE:
+ {{.HelpName}} [FLAGS] [TARGET]
+
+FLAGS:
+ {{range .VisibleFlags}}{{.}}
+ {{end}}
+EXAMPLES:
+ 1. Change the secret key for the access key "testkey"
+ {{.Prompt}} {{.HelpName}} myminio/ testkey --secret-key 'xxxxxxx'
+ 2. Change the expiry duration for the access key "testkey"
+ {{.Prompt}} {{.HelpName}} myminio/ testkey ---expiry-duration 24h
+`,
+}
+
+func mainAdminAccesskeyEdit(ctx *cli.Context) error {
+ return commonAccesskeyEdit(ctx)
+}
diff --git a/cmd/admin-accesskey-enable.go b/cmd/admin-accesskey-enable.go
new file mode 100644
index 0000000000..6a1eb2b281
--- /dev/null
+++ b/cmd/admin-accesskey-enable.go
@@ -0,0 +1,48 @@
+// Copyright (c) 2015-2024 MinIO, Inc.
+//
+// This file is part of MinIO Object Storage stack
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package cmd
+
+import (
+ "github.com/minio/cli"
+)
+
+var adminAccesskeyEnableCmd = cli.Command{
+ Name: "enable",
+ Usage: "enable an access key",
+ Action: mainAdminAccesskeyEnable,
+ Before: setGlobalsFromContext,
+ Flags: globalFlags,
+ OnUsageError: onUsageError,
+ CustomHelpTemplate: `NAME:
+ {{.HelpName}} - {{.Usage}}
+
+USAGE:
+ {{.HelpName}} [FLAGS] [TARGET]
+
+FLAGS:
+ {{range .VisibleFlags}}{{.}}
+ {{end}}
+EXAMPLES:
+ 1. Enable access key
+ {{.Prompt}} {{.HelpName}} myminio myaccesskey
+`,
+}
+
+func mainAdminAccesskeyEnable(ctx *cli.Context) error {
+ return enableDisableAccesskey(ctx, true)
+}
diff --git a/cmd/admin-accesskey-info.go b/cmd/admin-accesskey-info.go
new file mode 100644
index 0000000000..d0eb8d195c
--- /dev/null
+++ b/cmd/admin-accesskey-info.go
@@ -0,0 +1,50 @@
+// Copyright (c) 2015-2023 MinIO, Inc.
+//
+// This file is part of MinIO Object Storage stack
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package cmd
+
+import (
+ "github.com/minio/cli"
+)
+
+var adminAccesskeyInfoCmd = cli.Command{
+ Name: "info",
+ Usage: "info about given access key pairs",
+ Action: mainAdminAccesskeyInfo,
+ Before: setGlobalsFromContext,
+ Flags: globalFlags,
+ OnUsageError: onUsageError,
+ CustomHelpTemplate: `NAME:
+ {{.HelpName}} - {{.Usage}}
+
+USAGE:
+ {{.HelpName}} [FLAGS] TARGET ACCESSKEY [ACCESSKEY...]
+
+FLAGS:
+ {{range .VisibleFlags}}{{.}}
+ {{end}}
+EXAMPLES:
+ 1. Get info for the access key "testkey"
+ {{.Prompt}} {{.HelpName}} local/ testkey
+ 2. Get info for the access keys "testkey" and "testkey2"
+ {{.Prompt}} {{.HelpName}} local/ testkey testkey2
+ `,
+}
+
+func mainAdminAccesskeyInfo(ctx *cli.Context) error {
+ return commonAccesskeyInfo(ctx)
+}
diff --git a/cmd/admin-accesskey-list.go b/cmd/admin-accesskey-list.go
new file mode 100644
index 0000000000..4bcc7efdcb
--- /dev/null
+++ b/cmd/admin-accesskey-list.go
@@ -0,0 +1,168 @@
+// Copyright (c) 2015-2024 MinIO, Inc.
+//
+// This file is part of MinIO Object Storage stack
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package cmd
+
+import (
+ "strings"
+
+ "github.com/charmbracelet/lipgloss"
+ humanize "github.com/dustin/go-humanize"
+ "github.com/minio/cli"
+ json "github.com/minio/colorjson"
+ "github.com/minio/madmin-go/v3"
+ "github.com/minio/mc/pkg/probe"
+)
+
+var adminAccesskeyListFlags = []cli.Flag{
+ cli.BoolFlag{
+ Name: "users-only",
+ Usage: "only list user DNs",
+ },
+ cli.BoolFlag{
+ Name: "temp-only",
+ Usage: "only list temporary access keys",
+ },
+ cli.BoolFlag{
+ Name: "svcacc-only",
+ Usage: "only list service account access keys",
+ },
+ cli.BoolFlag{
+ Name: "self",
+ Usage: "list access keys for the authenticated user",
+ },
+ cli.BoolFlag{
+ Name: "all",
+ Usage: "list all access keys for all builtin users",
+ },
+}
+
+var adminAccesskeyListCmd = cli.Command{
+ Name: "list",
+ ShortName: "ls",
+ Usage: "list access key pairs for builtin users",
+ Action: mainAdminAccesskeyList,
+ Before: setGlobalsFromContext,
+ Flags: append(adminAccesskeyListFlags, globalFlags...),
+ OnUsageError: onUsageError,
+ CustomHelpTemplate: `NAME:
+ {{.HelpName}} - {{.Usage}}
+
+USAGE:
+ {{.HelpName}} [FLAGS] TARGET [DN...]
+
+FLAGS:
+ {{range .VisibleFlags}}{{.}}
+ {{end}}
+EXAMPLES:
+ 1. Get list of all builtin users and associated access keys in local server
+ {{.Prompt}} {{.HelpName}} local/ --all
+
+ 2. Get list of access keys for the authenticated user in local server
+ {{.Prompt}} {{.HelpName}} local/ --self
+
+ 3. Get list of builtin users in local server
+ {{.Prompt}} {{.HelpName}} local/ --all --users-only
+
+ 4. Get list of all builtin users and associated temporary access keys in play server (if admin)
+ {{.Prompt}} {{.HelpName}} play/ --temp-only
+
+ 5. Get list of access keys associated with user 'foobar'
+ {{.Prompt}} {{.HelpName}} play/ foobar
+
+ 6. Get list of access keys associated with users 'foobar' and 'tester'
+ {{.Prompt}} {{.HelpName}} play/ foobar tester
+
+ 7. Get all users and access keys if admin, else get authenticated user and associated access keys
+ {{.Prompt}} {{.HelpName}} local/
+`,
+}
+
+type userAccesskeyList struct {
+ Status string `json:"status"`
+ User string `json:"user"`
+ STSKeys []madmin.ServiceAccountInfo `json:"stsKeys"`
+ ServiceAccounts []madmin.ServiceAccountInfo `json:"svcaccs"`
+ LDAP bool `json:"ldap,omitempty"`
+}
+
+func (m userAccesskeyList) String() string {
+ labelStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#04B575"))
+ o := strings.Builder{}
+
+ userStr := "User"
+ if m.LDAP {
+ userStr = "DN"
+ }
+ o.WriteString(iFmt(0, "%s %s\n", labelStyle.Render(userStr+":"), m.User))
+ if len(m.STSKeys) > 0 || len(m.ServiceAccounts) > 0 {
+ o.WriteString(iFmt(2, "%s\n", labelStyle.Render("Access Keys:")))
+ }
+ for _, k := range m.STSKeys {
+ expiration := "never"
+ if nilExpiry(k.Expiration) != nil {
+ expiration = humanize.Time(*k.Expiration)
+ }
+ o.WriteString(iFmt(4, "%s, expires: %s, sts: true\n", k.AccessKey, expiration))
+ }
+ for _, k := range m.ServiceAccounts {
+ expiration := "never"
+ if nilExpiry(k.Expiration) != nil {
+ expiration = humanize.Time(*k.Expiration)
+ }
+ o.WriteString(iFmt(4, "%s, expires: %s, sts: false\n", k.AccessKey, expiration))
+ }
+
+ return o.String()
+}
+
+func (m userAccesskeyList) JSON() string {
+ jsonMessageBytes, e := json.MarshalIndent(m, "", " ")
+ fatalIf(probe.NewError(e), "Unable to marshal into JSON.")
+
+ return string(jsonMessageBytes)
+}
+
+func mainAdminAccesskeyList(ctx *cli.Context) error {
+ aliasedURL, tentativeAll, users, opts := commonAccesskeyList(ctx)
+
+ // Create a new MinIO Admin Client
+ client, err := newAdminClient(aliasedURL)
+ fatalIf(err, "Unable to initialize admin connection.")
+
+ accessKeysMap, e := client.ListAccessKeysBulk(globalContext, users, opts)
+ if e != nil {
+ if e.Error() == "Access Denied." && tentativeAll {
+ // retry with self
+ opts.All = false
+ accessKeysMap, e = client.ListAccessKeysBulk(globalContext, users, opts)
+ }
+ fatalIf(probe.NewError(e), "Unable to list access keys.")
+ }
+
+ for user, accessKeys := range accessKeysMap {
+ m := userAccesskeyList{
+ Status: "success",
+ User: user,
+ ServiceAccounts: accessKeys.ServiceAccounts,
+ STSKeys: accessKeys.STSKeys,
+ LDAP: false,
+ }
+ printMsg(m)
+ }
+ return nil
+}
diff --git a/cmd/admin-accesskey-remove.go b/cmd/admin-accesskey-remove.go
new file mode 100644
index 0000000000..38ca1323bb
--- /dev/null
+++ b/cmd/admin-accesskey-remove.go
@@ -0,0 +1,49 @@
+// Copyright (c) 2015-2024 MinIO, Inc.
+//
+// This file is part of MinIO Object Storage stack
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package cmd
+
+import (
+ "github.com/minio/cli"
+)
+
+var adminAccesskeyRemoveCmd = cli.Command{
+ Name: "remove",
+ ShortName: "rm",
+ Usage: "delete access key pairs for builtin users",
+ Action: mainAdminAccesskeyRemove,
+ Before: setGlobalsFromContext,
+ Flags: globalFlags,
+ OnUsageError: onUsageError,
+ CustomHelpTemplate: `NAME:
+ {{.HelpName}} - {{.Usage}}
+
+USAGE:
+ {{.HelpName}} [FLAGS] TARGET ACCESSKEY
+
+FLAGS:
+ {{range .VisibleFlags}}{{.}}
+ {{end}}
+EXAMPLES:
+ 1. Remove the access key "testkey" from local server
+ {{.Prompt}} {{.HelpName}} local/ testkey
+ `,
+}
+
+func mainAdminAccesskeyRemove(ctx *cli.Context) error {
+ return commonAccesskeyRemove(ctx)
+}
diff --git a/cmd/admin-accesskey.go b/cmd/admin-accesskey.go
new file mode 100644
index 0000000000..b5f0a0e189
--- /dev/null
+++ b/cmd/admin-accesskey.go
@@ -0,0 +1,45 @@
+// Copyright (c) 2015-2024 MinIO, Inc.
+//
+// This file is part of MinIO Object Storage stack
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package cmd
+
+import "github.com/minio/cli"
+
+var adminAccesskeySubcommands = []cli.Command{
+ adminAccesskeyListCmd,
+ adminAccesskeyRemoveCmd,
+ adminAccesskeyInfoCmd,
+ adminAccesskeyCreateCmd,
+ adminAccesskeyEditCmd,
+ adminAccesskeyEnableCmd,
+ adminAccesskeyDisableCmd,
+}
+
+var adminAccesskeyCmd = cli.Command{
+ Name: "accesskey",
+ Usage: "manage access keys defined in the MinIO server",
+ Action: mainAdminAccesskey,
+ Before: setGlobalsFromContext,
+ Flags: globalFlags,
+ Subcommands: adminAccesskeySubcommands,
+ HideHelpCommand: true,
+}
+
+func mainAdminAccesskey(ctx *cli.Context) error {
+ commandNotFound(ctx, adminAccesskeySubcommands)
+ return nil
+}
diff --git a/cmd/admin-main.go b/cmd/admin-main.go
index ecb98f6fca..af237b5374 100644
--- a/cmd/admin-main.go
+++ b/cmd/admin-main.go
@@ -56,6 +56,7 @@ var adminCmdSubcommands = []cli.Command{
adminClusterCmd,
adminRebalanceCmd,
adminLogsCmd,
+ adminAccesskeyCmd,
}
var adminCmd = cli.Command{
diff --git a/cmd/auto-complete.go b/cmd/auto-complete.go
index 3d54a01f73..5c633fb975 100644
--- a/cmd/auto-complete.go
+++ b/cmd/auto-complete.go
@@ -392,6 +392,16 @@ var completeCmds = map[string]complete.Predictor{
"/idp/ldap/accesskey/enable": aliasCompleter,
"/idp/ldap/accesskey/disable": aliasCompleter,
+ "/admin/accesskey/create": aliasCompleter,
+ "/admin/accesskey/list": aliasCompleter,
+ "/admin/accesskey/ls": aliasCompleter,
+ "/admin/accesskey/remove": aliasCompleter,
+ "/admin/accesskey/rm": aliasCompleter,
+ "/admin/accesskey/info": aliasCompleter,
+ "/admin/accesskey/edit": aliasCompleter,
+ "/admin/accesskey/enable": aliasCompleter,
+ "/admin/accesskey/disable": aliasCompleter,
+
"/admin/policy/info": aliasCompleter,
"/admin/policy/update": aliasCompleter,
"/admin/policy/add": aliasCompleter,
diff --git a/cmd/idp-ldap-accesskey-create.go b/cmd/idp-ldap-accesskey-create.go
index dcb690fe94..f86724de32 100644
--- a/cmd/idp-ldap-accesskey-create.go
+++ b/cmd/idp-ldap-accesskey-create.go
@@ -98,6 +98,10 @@ EXAMPLES:
}
func mainIDPLdapAccesskeyCreate(ctx *cli.Context) error {
+ return commonAccesskeyCreate(ctx, true)
+}
+
+func commonAccesskeyCreate(ctx *cli.Context, ldap bool) error {
if len(ctx.Args()) == 0 || len(ctx.Args()) > 2 {
showCommandHelpAndExit(ctx, 1) // last argument is exit code
}
@@ -114,7 +118,13 @@ func mainIDPLdapAccesskeyCreate(ctx *cli.Context) error {
client, err := newAdminClient(aliasedURL)
fatalIf(err, "Unable to initialize admin connection.")
- res, e := client.AddServiceAccountLDAP(globalContext, opts)
+ var res madmin.Credentials
+ var e error
+ if ldap {
+ res, e = client.AddServiceAccountLDAP(globalContext, opts)
+ } else {
+ res, e = client.AddServiceAccount(globalContext, opts)
+ }
fatalIf(probe.NewError(e), "Unable to add service account.")
m := ldapAccesskeyMessage{
diff --git a/cmd/idp-ldap-accesskey-edit.go b/cmd/idp-ldap-accesskey-edit.go
index 2a8680a3e5..9b3fb3785b 100644
--- a/cmd/idp-ldap-accesskey-edit.go
+++ b/cmd/idp-ldap-accesskey-edit.go
@@ -82,6 +82,10 @@ EXAMPLES:
}
func mainIDPLdapAccesskeyEdit(ctx *cli.Context) error {
+ return commonAccesskeyEdit(ctx)
+}
+
+func commonAccesskeyEdit(ctx *cli.Context) error {
if len(ctx.Args()) == 0 || len(ctx.Args()) > 2 {
showCommandHelpAndExit(ctx, 1) // last argument is exit code
}
@@ -115,6 +119,10 @@ func accessKeyEditOpts(ctx *cli.Context) madmin.UpdateServiceAccountReq {
description := ctx.String("description")
expDurVal := ctx.Duration("expiry-duration")
+ if name == "" && expVal == "" && expDurVal == 0 && policyPath == "" && secretKey == "" && description == "" {
+ fatalIf(probe.NewError(errors.New("At least one property must be edited")), "invalid flags")
+ }
+
if expVal != "" && expDurVal != 0 {
fatalIf(probe.NewError(errors.New("Only one of --expiry or --expiry-duration can be specified")), "invalid flags")
}
diff --git a/cmd/idp-ldap-accesskey-info.go b/cmd/idp-ldap-accesskey-info.go
index 67f42e873a..02f99721eb 100644
--- a/cmd/idp-ldap-accesskey-info.go
+++ b/cmd/idp-ldap-accesskey-info.go
@@ -120,6 +120,11 @@ func (m ldapAccesskeyMessage) JSON() string {
}
func mainIDPLdapAccesskeyInfo(ctx *cli.Context) error {
+ return commonAccesskeyInfo(ctx)
+}
+
+// currently no difference between ldap and builtin accesskey info
+func commonAccesskeyInfo(ctx *cli.Context) error {
if len(ctx.Args()) < 2 {
showCommandHelpAndExit(ctx, 1) // last argument is exit code
}
@@ -151,9 +156,8 @@ func mainIDPLdapAccesskeyInfo(ctx *cli.Context) error {
Policy: json.RawMessage(tempRes.Policy),
Name: tempRes.Name,
Description: tempRes.Description,
- Expiration: tempRes.Expiration,
+ Expiration: nilExpiry(tempRes.Expiration),
}
-
printMsg(m)
}
} else {
@@ -167,12 +171,18 @@ func mainIDPLdapAccesskeyInfo(ctx *cli.Context) error {
Policy: json.RawMessage(res.Policy),
Name: res.Name,
Description: res.Description,
- Expiration: res.Expiration,
+ Expiration: nilExpiry(res.Expiration),
}
-
printMsg(m)
}
}
return nil
}
+
+func nilExpiry(expiry *time.Time) *time.Time {
+ if expiry != nil && expiry.Equal(timeSentinel) {
+ return nil
+ }
+ return expiry
+}
diff --git a/cmd/idp-ldap-accesskey-list.go b/cmd/idp-ldap-accesskey-list.go
index 0a6224216d..aa6b20af21 100644
--- a/cmd/idp-ldap-accesskey-list.go
+++ b/cmd/idp-ldap-accesskey-list.go
@@ -19,12 +19,8 @@ package cmd
import (
"errors"
- "strings"
- "github.com/charmbracelet/lipgloss"
- "github.com/dustin/go-humanize"
"github.com/minio/cli"
- json "github.com/minio/colorjson"
"github.com/minio/madmin-go/v3"
"github.com/minio/mc/pkg/probe"
)
@@ -70,10 +66,10 @@ FLAGS:
{{range .VisibleFlags}}{{.}}
{{end}}
EXAMPLES:
- 1. Get list of all users and associated access keys in local server (if admin)
+ 1. Get list of all LDAP users and associated access keys in local server (if admin)
{{.Prompt}} {{.HelpName}} local/
- 2. Get list of users in local server (if admin)
+ 2. Get list of LDAP users in local server (if admin)
{{.Prompt}} {{.HelpName}} local/ --users-only
3. Get list of all users and associated temporary access keys in play server (if admin)
@@ -93,47 +89,37 @@ EXAMPLES:
`,
}
-type ldapUsersList struct {
- Status string `json:"status"`
- DN string `json:"dn"`
- STSKeys []madmin.ServiceAccountInfo `json:"stsKeys"`
- ServiceAccounts []madmin.ServiceAccountInfo `json:"svcaccs"`
-}
+func mainIDPLdapAccesskeyList(ctx *cli.Context) error {
+ aliasedURL, tentativeAll, users, opts := commonAccesskeyList(ctx)
-func (m ldapUsersList) String() string {
- labelStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#04B575"))
- o := strings.Builder{}
+ // Create a new MinIO Admin Client
+ client, err := newAdminClient(aliasedURL)
+ fatalIf(err, "Unable to initialize admin connection.")
- o.WriteString(iFmt(0, "%s %s\n", labelStyle.Render("DN:"), m.DN))
- if len(m.STSKeys) > 0 || len(m.ServiceAccounts) > 0 {
- o.WriteString(iFmt(2, "%s\n", labelStyle.Render("Access Keys:")))
- }
- for _, k := range m.STSKeys {
- expiration := "never"
- if k.Expiration != nil {
- expiration = humanize.Time(*k.Expiration)
+ accessKeysMap, e := client.ListAccessKeysLDAPBulkWithOpts(globalContext, users, opts)
+ if e != nil {
+ if e.Error() == "Access Denied." && tentativeAll {
+ // retry with self
+ opts.All = false
+ accessKeysMap, e = client.ListAccessKeysLDAPBulkWithOpts(globalContext, users, opts)
}
- o.WriteString(iFmt(4, "%s, expires: %s, sts: true\n", k.AccessKey, expiration))
+ fatalIf(probe.NewError(e), "Unable to list access keys.")
}
- for _, k := range m.ServiceAccounts {
- expiration := "never"
- if k.Expiration != nil {
- expiration = humanize.Time(*k.Expiration)
+
+ for dn, accessKeys := range accessKeysMap {
+ m := userAccesskeyList{
+ Status: "success",
+ User: dn,
+ ServiceAccounts: accessKeys.ServiceAccounts,
+ STSKeys: accessKeys.STSKeys,
+ LDAP: true,
}
- o.WriteString(iFmt(4, "%s, expires: %s, sts: false\n", k.AccessKey, expiration))
+ printMsg(m)
}
-
- return o.String()
-}
-
-func (m ldapUsersList) JSON() string {
- jsonMessageBytes, e := json.MarshalIndent(m, "", " ")
- fatalIf(probe.NewError(e), "Unable to marshal into JSON.")
-
- return string(jsonMessageBytes)
+ return nil
}
-func mainIDPLdapAccesskeyList(ctx *cli.Context) error {
+func commonAccesskeyList(ctx *cli.Context) (aliasedURL string, tentativeAll bool, users []string, opts madmin.ListAccessKeysOpts) {
if len(ctx.Args()) == 0 {
showCommandHelpAndExit(ctx, 1) // last argument is exit code
}
@@ -142,18 +128,18 @@ func mainIDPLdapAccesskeyList(ctx *cli.Context) error {
stsOnly := ctx.Bool("temp-only")
svcaccOnly := ctx.Bool("svcacc-only")
selfFlag := ctx.Bool("self")
- allFlag := ctx.Bool("all")
+ opts.All = ctx.Bool("all")
args := ctx.Args()
- aliasedURL := args.Get(0)
- users := args.Tail()
+ aliasedURL = args.Get(0)
+ users = args.Tail()
var e error
if (usersOnly && svcaccOnly) || (usersOnly && stsOnly) || (svcaccOnly && stsOnly) {
e = errors.New("only one of --users-only, --temp-only, or --permanent-only can be specified")
- } else if selfFlag && allFlag {
+ } else if selfFlag && opts.All {
e = errors.New("only one of --self or --all can be specified")
- } else if (selfFlag || allFlag) && len(users) > 0 {
+ } else if (selfFlag || opts.All) && len(users) > 0 {
e = errors.New("user DNs cannot be specified with --self or --all")
}
fatalIf(probe.NewError(e), "Invalid flags.")
@@ -161,45 +147,21 @@ func mainIDPLdapAccesskeyList(ctx *cli.Context) error {
// If no users/self/all flags are specified, tentatively assume --all
// If access is denied on tentativeAll, retry with self
// This is to maintain compatibility with the previous behavior
- tentativeAll := false
- if !selfFlag && !allFlag && len(users) == 0 {
+ if !selfFlag && !opts.All && len(users) == 0 {
tentativeAll = true
- allFlag = true
+ opts.All = true
}
- var listType string
switch {
case usersOnly:
- listType = madmin.AccessKeyListUsersOnly
+ opts.ListType = madmin.AccessKeyListUsersOnly
case stsOnly:
- listType = madmin.AccessKeyListSTSOnly
+ opts.ListType = madmin.AccessKeyListSTSOnly
case svcaccOnly:
- listType = madmin.AccessKeyListSvcaccOnly
+ opts.ListType = madmin.AccessKeyListSvcaccOnly
default:
- listType = madmin.AccessKeyListAll
- }
-
- // Create a new MinIO Admin Client
- client, err := newAdminClient(aliasedURL)
- fatalIf(err, "Unable to initialize admin connection.")
-
- accessKeysMap, e := client.ListAccessKeysLDAPBulk(globalContext, users, listType, allFlag)
- if e != nil {
- if e.Error() == "Access Denied." && tentativeAll {
- // retry with self
- accessKeysMap, e = client.ListAccessKeysLDAPBulk(globalContext, users, listType, false)
- }
- fatalIf(probe.NewError(e), "Unable to list access keys.")
+ opts.ListType = madmin.AccessKeyListAll
}
- for dn, accessKeys := range accessKeysMap {
- m := ldapUsersList{
- Status: "success",
- DN: dn,
- ServiceAccounts: accessKeys.ServiceAccounts,
- STSKeys: accessKeys.STSKeys,
- }
- printMsg(m)
- }
- return nil
+ return aliasedURL, tentativeAll, users, opts
}
diff --git a/cmd/idp-ldap-accesskey-remove.go b/cmd/idp-ldap-accesskey-remove.go
index 8f4d57b667..73f39e2310 100644
--- a/cmd/idp-ldap-accesskey-remove.go
+++ b/cmd/idp-ldap-accesskey-remove.go
@@ -46,6 +46,11 @@ EXAMPLES:
}
func mainIDPLdapAccesskeyRemove(ctx *cli.Context) error {
+ return commonAccesskeyRemove(ctx)
+}
+
+// No difference between ldap and builtin accesskey remove for now
+func commonAccesskeyRemove(ctx *cli.Context) error {
if len(ctx.Args()) != 2 {
showCommandHelpAndExit(ctx, 1) // last argument is exit code
}