Skip to content
This repository has been archived by the owner on Jan 8, 2024. It is now read-only.

Commit

Permalink
Merge pull request #1848 from hashicorp/feature/login-token
Browse files Browse the repository at this point in the history
internal/cli: waypoint login supports tokens
  • Loading branch information
mitchellh authored Jul 14, 2021
2 parents c978fb4 + 99d9178 commit 97f308b
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .changelog/1848.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:feature
cli: can login with a token using the new `waypoint login` command
```
79 changes: 76 additions & 3 deletions internal/cli/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type LoginCommand struct {
*baseCommand

flagAuthMethod string
flagToken string
}

func (c *LoginCommand) Run(args []string) int {
Expand Down Expand Up @@ -57,8 +58,18 @@ func (c *LoginCommand) Run(args []string) int {
return 1
}

// Login with OIDC
token, exitCode := c.loginOIDC()
// Determine our auth func, which by default is OIDC
var authFunc func() (string, int)
switch {
case c.flagToken != "":
authFunc = c.loginToken

default:
authFunc = c.loginOIDC
}

// Log in
token, exitCode := authFunc()
if exitCode > 0 {
return exitCode
}
Expand All @@ -67,6 +78,12 @@ func (c *LoginCommand) Run(args []string) int {
// which is already configured with the basic server connection stuff
// from this command.
newContext := c.flagConnection
if c.clientContext != nil {
// clientContext is always set to our actual context we used to
// create our client. So this will accurately grab non-flag based
// access i.e. loading our default context.
newContext = *c.clientContext
}
newContext.Server.AuthToken = token
newContext.Server.RequireAuth = true

Expand All @@ -93,6 +110,41 @@ func (c *LoginCommand) Run(args []string) int {
return 0
}

func (c *LoginCommand) loginToken() (string, int) {
// First we decode the token to ensure it is valid and also to figure
// out if we have a login or invite token.
decodeResp, err := c.project.Client().DecodeToken(c.Ctx, &pb.DecodeTokenRequest{
Token: c.flagToken,
})
if err != nil {
c.ui.Output(clierrors.Humanize(err), terminal.WithErrorStyle())
return "", 1
}
token := decodeResp.Token

// If we have a login token, then we're just done cause that can be stored directly.
if _, ok := token.Kind.(*pb.Token_Login_); ok {
return c.flagToken, 0
}

// Then it must be an invite token
if _, ok := token.Kind.(*pb.Token_Invite_); !ok {
c.ui.Output(strings.TrimSpace(errTokenInvalid), terminal.WithErrorStyle())
return "", 1
}

// Convert it
convertResp, err := c.project.Client().ConvertInviteToken(c.Ctx, &pb.ConvertInviteTokenRequest{
Token: c.flagToken,
})
if err != nil {
c.ui.Output(clierrors.Humanize(err), terminal.WithErrorStyle())
return "", 1
}

return convertResp.Token, 0
}

func (c *LoginCommand) loginOIDC() (string, int) {
// Get our OIDC auth methods
respList, err := c.project.Client().ListOIDCAuthMethods(c.Ctx, &empty.Empty{})
Expand Down Expand Up @@ -146,6 +198,8 @@ func (c *LoginCommand) loginOIDC() (string, int) {
}

// Open the auth URL in the user browser or ask them to visit it.
// We purposely use fmt here and NOT c.ui because the ui will truncate
// our URL (a known bug).
fmt.Printf(strings.TrimSpace(outVisitURL)+"\n\n", respURL.Url)
if err := util.OpenURL(respURL.Url); err != nil {
c.Log.Warn("error opening auth url", "err", err)
Expand Down Expand Up @@ -186,6 +240,13 @@ func (c *LoginCommand) Flags() *flag.Sets {
Usage: "Auth method to use for login. This will default to " +
"the only available auth method if only one exists.",
})

f.StringVar(&flag.StringVar{
Name: "token",
Target: &c.flagToken,
Usage: "Auth with a token. This will force auth-method to 'token'. " +
"This works with both login and invite tokens.",
})
})
}

Expand All @@ -207,17 +268,24 @@ Usage: waypoint login [server address]
Log in to a Waypoint server.
This is usually the first command a new user runs to gain CLI access to
an existing Waypoint server.
If the server address is not specified and you have an active
context (see "waypoint context"), then this command will reauthenticate
to the currently active server.
This command can be used for token-based authentication as well as
other forms such as OIDC. You can use "-token" to specify a login or
invite token and configure the CLI to access the server.
` + c.Flags().Help())
}

const (
errNoAuthMethods = `
Only token-based authentication is allowed by this server. To login using
a token, use the "waypoint context create" command.
a token, use the "waypoint login" command with the "-token" flag.
`

errManyAuthMethods = `
Expand All @@ -238,6 +306,11 @@ waypoint login example.com
or
waypoint login https://example.com
`

errTokenInvalid = `
The specified token is not a valid login or invite token. Please
double-check the token and try again.
`

outVisitURL = `
Expand Down

0 comments on commit 97f308b

Please sign in to comment.