Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Credential Handling Improvements #205

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c737291
Inline configureClientCredentialTokenSource nd explicitly assign clie…
tobias-hashicorp Oct 18, 2023
be67cdb
Rename secret_id to client_secret
tobias-hashicorp Oct 18, 2023
5415d09
Introduce a common cache used for all kinds of login
tobias-hashicorp Oct 25, 2023
9088632
Move client credential config creation into setTokenSource
tobias-hashicorp Oct 25, 2023
550ec9c
Move the construction of the workload identity provider into setToken…
tobias-hashicorp Oct 25, 2023
cc236fc
Use the new caching mechanism for all token sources
tobias-hashicorp Oct 25, 2023
3cdf338
Delete the user session struct
tobias-hashicorp Oct 25, 2023
70bdf8b
Garbage collect expired tokens
tobias-hashicorp Oct 26, 2023
11795ef
Remove ErrorNoLocalCredsFound error
tobias-hashicorp Oct 26, 2023
b43e700
Introduce ForceLogion option
tobias-hashicorp Oct 26, 2023
e9bd946
Expand example command to explicitly create HCP config
tobias-hashicorp Oct 26, 2023
ab810c7
Rename example cmd to example
tobias-hashicorp Oct 26, 2023
7c32bd0
Split setTokenSource into two methods
tobias-hashicorp Oct 26, 2023
f5ee73b
Move token source logic into own file and add more tests
tobias-hashicorp Oct 26, 2023
249a701
Delete unused mocks, rename variables and fix imports
tobias-hashicorp Oct 26, 2023
96ba6e9
Move borwser token source to the top of the file
tobias-hashicorp Oct 27, 2023
9816318
Better structure file, folder and mode constants
tobias-hashicorp Oct 27, 2023
3de150d
Improve evaluate function
tobias-hashicorp Oct 27, 2023
7e48797
Rename evaluate to getValidToken
tobias-hashicorp Oct 27, 2023
21e52cd
Move refresh timeout into constant and set it
tobias-hashicorp Oct 27, 2023
c4080fe
Add a minimum TTL
tobias-hashicorp Oct 27, 2023
f9e52ac
Don't consider a missing cache file an error
tobias-hashicorp Oct 27, 2023
1b2f137
Document that removeExpiredTokens will not automatically write to disk
tobias-hashicorp Oct 27, 2023
b4e27f9
Use loginSourceType instead of login boolean flag
tobias-hashicorp Oct 27, 2023
fa1ab6b
Update documentation to reflect new cache implementation
tobias-hashicorp Oct 27, 2023
e0e31d4
Use creds-cache.json in cache tests
tobias-hashicorp Oct 27, 2023
8767256
Add change log entry for credential caching changes
tobias-hashicorp Oct 27, 2023
e1aa5c4
Write the cache directly after removing expired credentials
tobias-hashicorp Oct 27, 2023
19a371c
Merge branch 'main' into tobias/plat-1424/credential-handling-improve…
tobias-hashicorp Oct 27, 2023
fb37946
Allow to set a custom token source
tobias-hashicorp Oct 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changelog/205.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
```release-note:improvement
All credentials (login, service-principal and workload identity provider) are now cached.

The cache file has moved to `creds-cache.json` to not interfere with applications that rely on the previous cache file
structure.

It is further now possible to enforce an interactive login (via a configuration flag), which can be used to implement a
`cli login` functionality.
```
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ User session is ideal for getting started or one-off usage. It also works for lo

To obtain user credentials, the client credential environment variables `HCP_CLIENT_ID` and `HCP_CLIENT_SECRET` must be unset. When no client credentials are detected, the HCP Go client will prompt the user with a browser login window. Once authenticated, the user session stays refreshed without intervention until it expires after 24 hours.

If you have a use-case with the SDK to leverage the browser login as a feature but want to control if the browser is opened, or even to understand if the system already has a valid token present, you can pass in the option func of `WithoutBrowserLogin()` to your `NewHCPConfig()`. This will use either the provided `ClientID`:`ClientSecret` combo or a valid token that has been previously written to the system. If neither option exists, then `auth.ErrorNoLocalCredsFound` is returned to indicate that the user is not yet logged in.
If you have a use-case with the SDK to leverage the browser login as a feature but want to control if the browser is opened you can pass in the option func of `WithoutBrowserLogin()` to your `NewHCPConfig()`.

### User Profile

Expand Down Expand Up @@ -66,7 +66,7 @@ HCP_ORGANIZATION_ID="22abc..."
)
```

See `cmd/hcp-sdk-go-client` for a complete example.
See `cmd/example` for a complete example.

### SDK Release Cycle

Expand Down Expand Up @@ -96,9 +96,7 @@ In addition to the generated product clients, the HCP Go SDK provides a few libr

### Cache

The Cache interface lives under the `auth` package. It handles writing the user credentials obtained during browser login to the common location `/.config/hcp/credentials.json` in the home directory. The Cache has `Read` and `Write` methods that can be used to get and set stored HCP credentials.

Generally the contents of the Cache should be Read to get the latest, unexpired credentials. Without care, overwriting user credentials may cause unexpected authentication failures.
The Cache interface lives under the `tokencache` package. It handles writing the user, service-principal and workload identity provider tokens to the common location `/.config/hcp/creds-cache.json` in the home directory. The cached values are automatically read and written when a caching token source is used.

## Contributing

Expand Down
31 changes: 16 additions & 15 deletions auth/browser.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,22 @@ import (
"golang.org/x/oauth2"
)

// Browser implements the browser handler for the OAuth2 login flow.
type Browser interface {
GetTokenFromBrowser(context.Context, *oauth2.Config) (*oauth2.Token, error)
// browserLogin implements an oauth2.TokenSource for interactive browser logins.
type browserLogin struct {
oauthConfig *oauth2.Config
}

// NewBrowserLogin will return an oauth2.TokenSource that will return a Token from an interactive browser login.
func NewBrowserLogin(oauthConfig *oauth2.Config) *browserLogin {
return &browserLogin{
oauthConfig: oauthConfig,
}
}

// Token will return an oauth2.Token retrieved from an interactive browser login.
func (b *browserLogin) Token() (*oauth2.Token, error) {
browser := &oauthBrowser{}
return browser.GetTokenFromBrowser(context.Background(), b.oauthConfig)
}

// oauthBrowser implements the Browser interface using the real OAuth2 login flow.
Expand Down Expand Up @@ -85,18 +98,6 @@ func (b *oauthBrowser) GetTokenFromBrowser(ctx context.Context, conf *oauth2.Con
return nil, fmt.Errorf("failed to exchange code for token: %w", err)
}

// Save the token to config file.
cache := Cache{
AccessToken: tok.AccessToken,
RefreshToken: tok.RefreshToken,
AccessTokenExpiry: tok.Expiry,
SessionExpiry: time.Now().Add(SessionMaxAge),
}
err = Write(cache)
if err != nil {
return nil, fmt.Errorf("failed to write token to file: %w", err)
}

return tok, nil
case <-sigintCh:
return nil, errors.New("interrupted")
Expand Down
177 changes: 0 additions & 177 deletions auth/cache.go

This file was deleted.

Loading