This repository has been archived by the owner on May 18, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 224
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: One keyring item for session (#174)
* Add some notes and docstrings * Move original KeyringSessions to its own internal package * Avoid passing all profiles to sessioncache * remove sessioncache Delete * Refactor session cache into Key and Store parts * Rename Retrieve -> Get and Store -> Put * Flatten sessioncache package heirarchy * Add cache hit/miss/expired/error debug messages * add sessionCacheInterface * Add SingleKrItemStore * fix debug fmt * Add --session-cache-single-item * Fixes; remove versioned db We can cross that bridge when we come to it * docs * f: remove sequence number * Clean up; add missing error handling * Add sessioncache store tests Introduces golang.org/x/xerrors, until we can start to use go 1.13 errors reliably. * Remove dependency on github.com/pkg/errors Just use stdlib errors + xerrors
- Loading branch information
1 parent
11c2803
commit 6658fa0
Showing
16 changed files
with
496 additions
and
145 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package sessioncache | ||
|
||
import ( | ||
"crypto/md5" | ||
"encoding/hex" | ||
"encoding/json" | ||
"fmt" | ||
"time" | ||
) | ||
|
||
type OrigKey struct { | ||
ProfileName string | ||
ProfileConf map[string]string | ||
Duration time.Duration | ||
} | ||
|
||
// Key returns a key for the keyring item. This is a string containing the source profile name, | ||
// the profile name, and a hash of the duration | ||
// | ||
// this is a copy of KeyringSessions.key and should preserve behavior, *except* that it assumes `profileName` | ||
// is a valid and existing profile name | ||
func (k OrigKey) Key() string { | ||
// nick: I don't understand this at all. This key function is roughly: | ||
// sourceProfileName + hex(md5(duration + json(profileConf))) | ||
// - why md5? | ||
// - why the JSON of the whole profile? (especially strange considering JSON map order is undetermined) | ||
// TODO(nick): document this | ||
var source string | ||
if source = k.ProfileConf["source_profile"]; source == "" { | ||
source = k.ProfileName | ||
} | ||
hasher := md5.New() | ||
hasher.Write([]byte(k.Duration.String())) | ||
|
||
enc := json.NewEncoder(hasher) | ||
enc.Encode(k.ProfileConf) | ||
|
||
return fmt.Sprintf("%s session (%x)", source, hex.EncodeToString(hasher.Sum(nil))[0:10]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// sessioncache caches sessions (sts.Credentials) | ||
// | ||
// sessioncache splits Stores (the way cache items are stored) from Keys | ||
// (the way cache items are looked up/replaced) | ||
package sessioncache | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
|
||
"github.com/aws/aws-sdk-go/service/sts" | ||
) | ||
|
||
// Session adds a session name to sts.Credentials | ||
type Session struct { | ||
Name string | ||
sts.Credentials | ||
} | ||
|
||
func (s *Session) Bytes() ([]byte, error) { | ||
return json.Marshal(s) | ||
} | ||
|
||
// Key is used to compute the cache key for a session | ||
type Key interface { | ||
Key() string | ||
} | ||
|
||
var ErrSessionExpired = errors.New("session expired") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package sessioncache | ||
|
||
import ( | ||
"encoding/json" | ||
"time" | ||
|
||
"github.com/99designs/keyring" | ||
log "github.com/sirupsen/logrus" | ||
|
||
// use xerrors until 1.13 is stable/oldest supported version | ||
"golang.org/x/xerrors" | ||
) | ||
|
||
// KrItemPerSessionStore stores one session in one keyring item | ||
// | ||
// This is the classic session store implementation. Its main drawback is that on macOS, | ||
// without code signing, you need to reauthorize the binary between upgrades *for each | ||
// item*. | ||
type KrItemPerSessionStore struct { | ||
Keyring keyring.Keyring | ||
} | ||
|
||
// Get returns the session from the keyring at k.Key() | ||
// | ||
// If the keyring item is not found, returns wrapped keyring.ErrKeyNotFound | ||
// | ||
// If the session is found, but is expired, returns wrapped ErrSessionExpired | ||
func (s *KrItemPerSessionStore) Get(k Key) (*Session, error) { | ||
keyStr := k.Key() | ||
item, err := s.Keyring.Get(keyStr) | ||
if err != nil { | ||
log.Debugf("cache get `%s`: miss (read error): %s", keyStr, err) | ||
return nil, xerrors.Errorf("failed Keyring.Get(%q): %w", keyStr, err) | ||
} | ||
|
||
var session Session | ||
|
||
if err = json.Unmarshal(item.Data, &session); err != nil { | ||
log.Debugf("cache get `%s`: miss (unmarshal error): %s", keyStr, err) | ||
return nil, xerrors.Errorf("failed unmarshal for %q: %w", keyStr, err) | ||
} | ||
|
||
if session.Expiration.Before(time.Now()) { | ||
log.Debugf("cache get `%s`: expired", keyStr) | ||
return nil, xerrors.Errorf("%q expired at %s: %w", keyStr, session.Expiration, ErrSessionExpired) | ||
} | ||
|
||
log.Debugf("cache get `%s`: hit", keyStr) | ||
return &session, nil | ||
} | ||
|
||
func (s *KrItemPerSessionStore) Put(k Key, session *Session) error { | ||
keyStr := k.Key() | ||
bytes, err := session.Bytes() | ||
if err != nil { | ||
log.Debugf("cache put `%s`: error (marshal): %s", keyStr, err) | ||
return err | ||
} | ||
|
||
log.Debugf("Writing session for %s to keyring", session.Name) | ||
item := keyring.Item{ | ||
Key: k.Key(), | ||
Label: "aws session for " + session.Name, | ||
Data: bytes, | ||
KeychainNotTrustApplication: false, | ||
} | ||
if err := s.Keyring.Set(item); err != nil { | ||
log.Debugf("cache put `%s`: error (write): %s", keyStr, err) | ||
return err | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package sessioncache | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/99designs/keyring" | ||
) | ||
|
||
func TestKrItemPerSessionStore(t *testing.T) { | ||
testStore(t, func() store { | ||
return &KrItemPerSessionStore{ | ||
Keyring: keyring.NewArrayKeyring([]keyring.Item{}), | ||
} | ||
}) | ||
} |
Oops, something went wrong.