Skip to content

Commit

Permalink
Add support to generate API token with tz api-token create
Browse files Browse the repository at this point in the history
Signed-off-by: Anuj Chaudhari <[email protected]>
  • Loading branch information
anujc25 committed Oct 4, 2024
1 parent 9896322 commit 60a3bf0
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 5 deletions.
8 changes: 8 additions & 0 deletions pkg/auth/common/login_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,14 @@ func WithOrgID(orgID string) LoginOption {
}
}

// WithClientID causes the login with given ClientID.
func WithClientID(clientID string) LoginOption {
return func(h *TanzuLoginHandler) error {
h.clientID = clientID
return nil
}
}

// WithCertInfo customizes cert verification information
func WithCertInfo(tlsSkipVerify bool, caCertData string) LoginOption {
return func(h *TanzuLoginHandler) error {
Expand Down
14 changes: 9 additions & 5 deletions pkg/auth/uaa/tanzu.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@ import (
const (
// Tanzu CLI client ID for UAA that has http://127.0.0.1/callback as the
// only allowed Redirect URI and does not have an associated client secret.
tanzuCLIClientID = "tp_cli_app"
tanzuCLIClientSecret = ""
defaultListenAddress = "127.0.0.1:0"
defaultCallbackPath = "/callback"
TanzuCLIClientID = "tp_cli_app"
// Alternate client ID for UAA associated with a longer refresh token
// validity. Use this for CLI use cases where it is impractical to
// interactively reauthenticated once the refresh token expires.
TanzuCLIClientIDExtended = "tp_cli_app" // TODO(vui) update once available.
tanzuCLIClientSecret = ""
defaultListenAddress = "127.0.0.1:0"
defaultCallbackPath = "/callback"
)

func getIssuerEndpoints(issuerURL string) common.IssuerEndPoints {
Expand All @@ -30,7 +34,7 @@ func getIssuerEndpoints(issuerURL string) common.IssuerEndPoints {
func TanzuLogin(issuerURL string, opts ...common.LoginOption) (*common.Token, error) {
issuerEndpoints := getIssuerEndpoints(issuerURL)

h := common.NewTanzuLoginHandler(issuerURL, issuerEndpoints.AuthURL, issuerEndpoints.TokenURL, tanzuCLIClientID, tanzuCLIClientSecret, defaultListenAddress, defaultCallbackPath, config.UAAIdpType, nil, nil, term.IsTerminal)
h := common.NewTanzuLoginHandler(issuerURL, issuerEndpoints.AuthURL, issuerEndpoints.TokenURL, TanzuCLIClientID, tanzuCLIClientSecret, defaultListenAddress, defaultCallbackPath, config.UAAIdpType, nil, nil, term.IsTerminal)
for _, opt := range opts {
if err := opt(h); err != nil {
return nil, err
Expand Down
88 changes: 88 additions & 0 deletions pkg/command/apitoken.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright 2024 VMware, Inc. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package command

import (
"fmt"
"time"

"github.com/fatih/color"
"github.com/pkg/errors"
"github.com/spf13/cobra"

"github.com/vmware-tanzu/tanzu-plugin-runtime/config"
"github.com/vmware-tanzu/tanzu-plugin-runtime/config/types"
"github.com/vmware-tanzu/tanzu-plugin-runtime/plugin"

commonauth "github.com/vmware-tanzu/tanzu-cli/pkg/auth/common"
"github.com/vmware-tanzu/tanzu-cli/pkg/auth/uaa"
"github.com/vmware-tanzu/tanzu-cli/pkg/cli"
"github.com/vmware-tanzu/tanzu-cli/pkg/constants"
)

func newAPITokenCmd() *cobra.Command {
apiTokenCmd := &cobra.Command{
Use: "api-token",
Short: "API Token Generation for the Tanzu Platform",
Aliases: []string{"apitoken"},
Annotations: map[string]string{
"group": string(plugin.SystemCmdGroup),
},
}

apiTokenCmd.SetUsageFunc(cli.SubCmdUsageFunc)
apiTokenCmd.AddCommand(
newAPITokenCreateCmd(),
)

return apiTokenCmd
}

func newAPITokenCreateCmd() *cobra.Command {
createCmd := &cobra.Command{
Use: "create",
Short: "Create new API Token",
Aliases: []string{},
RunE: createAPIToken,
}

return createCmd
}

func createAPIToken(cmd *cobra.Command, _ []string) (err error) {
c, err := config.GetActiveContext(types.ContextTypeTanzu)
if err != nil {
return errors.New("No active context of type `tanzu`. Please login to Tanzu Platform first to generate the API token")
}
if c == nil || c.GlobalOpts == nil || c.GlobalOpts.Auth.Issuer == "" {
return errors.New("Invalid active context of type `tanzu`. Please login to Tanzu Platform first to generate the API token")
}
// Make sure it is of type tanzu with tanzuIdpType as `uaa` else return error
if idpType, exist := c.AdditionalMetadata[config.TanzuIdpTypeKey]; !exist || idpType != "uaa" {
return errors.New("invalid IDP type for the active context. Only UAA IDP type is supported for generating API token")
}

var token *commonauth.Token
// If user chooses to use a specific local listener port, use it
// Also specify the client ID to use for token generation
loginOptions := []commonauth.LoginOption{
commonauth.WithListenerPortFromEnv(constants.TanzuCLIOAuthLocalListenerPort),
commonauth.WithClientID(uaa.TanzuCLIClientIDExtended),
}

token, err = uaa.TanzuLogin(c.GlobalOpts.Auth.Issuer, loginOptions...)
if err != nil {
return errors.Wrap(err, "unable to login")
}
cyanBold := color.New(color.FgCyan).Add(color.Bold)
bold := color.New(color.Bold)

fmt.Fprint(cmd.OutOrStdout(), bold.Sprint("==\n\n"))
fmt.Fprintf(cmd.OutOrStdout(), "%s Your generated API token is: %s\n\n", bold.Sprint("API Token Generation Successful!"), cyanBold.Sprint(token.RefreshToken))
fmt.Fprintf(cmd.OutOrStdout(), "%s The token will expire on %s.\n", bold.Sprint("Token Expiration:"), bold.Sprint(time.Now().Local().Add(time.Second*time.Duration(token.ExpiresIn))))
fmt.Fprint(cmd.OutOrStdout(), "Please copy and save your token securely. Note that you will need to regenerate a new token before expiration time and login again to continue using the CLI.\n\n")
fmt.Fprintf(cmd.OutOrStdout(), "For non-interactive login use the API token as follow: %s\n", cyanBold.Sprint("TANZU_API_TOKEN=<token> tanzu login --endpoint <tanzu-platform-endpoint>"))

return nil
}
1 change: 1 addition & 0 deletions pkg/command/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ func NewRootCmd() (*cobra.Command, error) { //nolint: gocyclo,funlen
newCompletionCmd(),
newConfigCmd(),
newContextCmd(),
newAPITokenCmd(),
k8sCmd,
tmcCmd,
opsCmd,
Expand Down

0 comments on commit 60a3bf0

Please sign in to comment.