Files
threshold/internal/cmd/commands/authenticate/funcs.go
T
Jim fba9d1cdf1 Add client daemon repo, server, and cmd
The commands added are:
boundary daemon start
boundary daemon stop
boundary daemon add-token
boundary daemon status
boundary search

If these actions are performed on a platform that doesn't support sqlite
natively in go an error is returned.

Besides some hooks into the cmd package all the significant logic
resides in internal/clientcache

feat (cmds/authenticate): output the token name when storing token

feat: update go-dbw which now uses pure go sqlite driver

refact (base.Command): export FlagOutputCurlString

Exporting FlagOutputCurlString allows other commands that embed
the base.Command to access the flag as needed

feat: add a cache Repository to manage cache storage

feat: add a "cache" CLI command

This new command will support both managing and searching the
local CLI cache daemon.

feat: start cache daemon as needed when issue CLI commands

Move files to new directories and add persona table (#3526)

* Add persona table and move files to new directories

Client daemon now uses unix sockets and update pathing (#3535)

* Add unix socket listen and dialers with file permissions applied

* Update the pathing to match RFC

Cache refreshing now uses all stored personas. (#3545)

Updating headers for LLB files

Decouple daemon and cache server (#3566)

* Separate daemon from server

* Add persona handler to daemon server (#3579)

Moved search to use mql and added tests for the search command (#3589)

* search uses hashicorp/mql

Windows support for client side daemon (#3618)

* exec.Command for background process

* Log to stderr when in foreground and file always

* Use pid files across platform for start and stop

Requests with version info must match the daemon's version (#3640)

* requests with version info must match daemons

Update dependencies and breakout cgo/pure go sqlite drivers  (#3657)

upgrade go-dbw deps and add cgo build tags

Enable graceful shutdown in windows (#3695)

* Enable graceful shutdown in windows

Co-authored-by: Jim <jlambert@hashicorp.com>

Targets delete when a persona changes address or user id (#3673)

* Handle cache refresh in repo

Add sessions to the client side cache (#3682)

* Add sessions to repository

* Search command supports sessions

* adding session related tests to db and refresh

Change cache schema from personas to tokens+users (#3737)

* Change from personas to tokens+users

* Separate keyring tokens from auth tokens

Add support for keyringless auth tokens (#3765)

* Add support for keyringless auth tokens

Remove expired auth tokens from cache (#3768)

* Remove expired auth tokens from cache

Complete the TODO of checking for inflight tx (#3779)

Delete tokens that the controller says are invalid (#3782)

fix search test with boundary token check (#3799)

Collect resource info in repository_<resource>s.go (#3769)

* Collect resource info in repository_<resource>s.go

* Move search logic into the domain (#3794)

Daemon and search restricted to supported platforms (#3801)

* Daemon and search restricted to supported platforms

Reorganize the clientcache packages (#3814)

* Refactor for self contained domain logic

* Put clientcache stuff under internal
2024-01-05 07:43:20 -08:00

131 lines
4.6 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package authenticate
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"strings"
"time"
"github.com/hashicorp/boundary/api/authmethods"
"github.com/hashicorp/boundary/api/authtokens"
"github.com/hashicorp/boundary/internal/cmd/base"
nkeyring "github.com/jefferai/keyring"
zkeyring "github.com/zalando/go-keyring"
)
func saveAndOrPrintToken(c *base.Command, result *authmethods.AuthenticateResult) int {
token := new(authtokens.AuthToken)
if err := json.Unmarshal(result.GetRawAttributes(), token); err != nil {
c.PrintCliError(fmt.Errorf("Error trying to decode response as an auth token: %w", err))
return base.CommandCliError
}
switch base.Format(c.UI) {
case "table":
c.UI.Output(base.WrapForHelpText([]string{
"",
"Authentication information:",
fmt.Sprintf(" Account ID: %s", token.AccountId),
fmt.Sprintf(" Auth Method ID: %s", token.AuthMethodId),
fmt.Sprintf(" Expiration Time: %s", token.ExpirationTime.Local().Format(time.RFC1123)),
fmt.Sprintf(" User ID: %s", token.UserId),
}))
case "json":
if ok := c.PrintJsonItem(result.GetResponse()); !ok {
return base.CommandCliError
}
return base.CommandSuccess
}
var gotErr bool
keyringType, tokenName, err := c.DiscoverKeyringTokenInfo()
if err != nil {
c.UI.Error(fmt.Sprintf("Error fetching keyring information: %s", err))
gotErr = true
} else if keyringType != "none" &&
tokenName != "none" &&
keyringType != "" &&
tokenName != "" {
marshaled, err := json.Marshal(token)
if err != nil {
c.UI.Error(fmt.Sprintf("Error marshaling auth token to save to keyring: %s", err))
gotErr = true
} else {
switch keyringType {
case "wincred", "keychain":
if err := zkeyring.Set(base.StoredTokenName, tokenName, base64.RawStdEncoding.EncodeToString(marshaled)); err != nil {
c.UI.Error(fmt.Sprintf("Error saving auth token to %q keyring: %s", keyringType, err))
gotErr = true
}
default:
krConfig := nkeyring.Config{
LibSecretCollectionName: "login",
PassPrefix: "HashiCorp_Boundary",
AllowedBackends: []nkeyring.BackendType{nkeyring.BackendType(keyringType)},
}
kr, err := nkeyring.Open(krConfig)
if err != nil {
c.UI.Error(fmt.Sprintf("Error opening %q keyring: %s", keyringType, err))
gotErr = true
break
}
if err := kr.Set(nkeyring.Item{
Key: tokenName,
Data: []byte(base64.RawStdEncoding.EncodeToString(marshaled)),
}); err != nil {
c.UI.Error(fmt.Sprintf("Error storing token in %q keyring: %s", keyringType, err))
gotErr = true
break
}
}
if !gotErr {
c.UI.Output(fmt.Sprintf("\nThe token name %q was successfully stored in the chosen keyring and is not displayed here.", tokenName))
}
}
}
switch {
case gotErr:
c.UI.Warn(fmt.Sprintf("The token was not successfully saved to a system keyring. The token is:\n\n%s\n\nIt must be manually passed in via the BOUNDARY_TOKEN env var or -token flag. Storing the token can also be disabled via -keyring-type=none.", token.Token))
case c.FlagKeyringType == "none":
c.UI.Warn("\nStoring the token in a keyring was disabled. The token is:")
c.UI.Output(token.Token)
c.UI.Warn("Please be sure to store it safely!")
}
return base.CommandSuccess
}
// getPrimaryAuthMethodId iterates over client.List() to find the primary auth method ID for the
// given scopeId. If scope ID is empty or no primary auth method is found, it returns an error.
func getPrimaryAuthMethodId(ctx context.Context, client *authmethods.Client, scopeId, amType string) (string, error) {
if scopeId == "" {
return "", fmt.Errorf("Must pass a non empty scope ID string to GetPrimaryAuthMethodId()")
}
authMethodListResult, err := client.List(ctx, scopeId)
if err != nil {
return "", err
}
for _, m := range authMethodListResult.GetItems() {
if m.IsPrimary {
if !strings.HasPrefix(m.Id, amType) {
return "", fmt.Errorf("Error looking up primary auth method in scope '%s': got '%s' but the command requires an auth method prefix of '%s'. Make sure the sub command you're using matches the primary auth method type in the scope being used. For example, if using the password sub command the primary auth method must have a prefix of 'ampw'.\n\nSee 'boundary authenticate -h' for available sub command usage.", scopeId, m.Id, amType)
}
return m.Id, nil
}
}
return "", fmt.Errorf("Primary auth method not found for scope ID: '%s'. Please set a primary auth method on this scope or pass one explicitly using an authenticate sub command (see 'boundary authenticate -h') along with the -auth-method-id flag.", scopeId)
}