Skip to content

Commit

Permalink
OCM-4965 | feat: Secure Store additional error handling and removal o…
Browse files Browse the repository at this point in the history
…f keys
  • Loading branch information
tylercreller committed Feb 5, 2024
1 parent d2c86e1 commit f7ad280
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 13 deletions.
66 changes: 56 additions & 10 deletions authentication/securestore/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,21 @@ const (
MaxWindowsByteSize = 2500 // Windows Credential Manager has a 2500 byte limit
)

var (
ErrNoBackendsAvailable = fmt.Errorf("no backends available, expected one of %v", allowedBackends)
// The order of the backends is important. The first backend in the list is the first one
// that will attempt to be used.
allowedBackends = []keyring.BackendType{
keyring.WinCredBackend,
keyring.KeychainBackend,
keyring.SecretServiceBackend,
keyring.PassBackend,
}
)

func getKeyringConfig() keyring.Config {
return keyring.Config{
// The order of the backends is important. The first backend in the list is the first one
// that will attempt to be used.
AllowedBackends: []keyring.BackendType{
keyring.WinCredBackend,
keyring.KeychainBackend,
keyring.SecretServiceBackend,
keyring.PassBackend,
},
AllowedBackends: allowedBackends,
// Generic
ServiceName: ItemKey,
// MacOS
Expand All @@ -48,16 +53,27 @@ func getKeyringConfig() keyring.Config {
// The first backend in the slice is the first one that will be used.
func AvailableBackends() []string {
b := []string{}
for _, k := range keyring.AvailableBackends() {
b = append(b, string(k))

// Intersection between available backends from OS and allowed backends
for _, avail := range keyring.AvailableBackends() {
for _, allowed := range allowedBackends {
if avail == allowed {
b = append(b, string(allowed))
}
}
}

return b
}

// UpsertConfigToKeyring will upsert the provided credentials to first priority OS secure store.
//
// Note: CGO_ENABLED=1 is required for OSX Keychain and darwin builds
func UpsertConfigToKeyring(creds []byte) error {
if err := validateBackends(); err != nil {
return err
}

ring, err := keyring.Open(getKeyringConfig())
if err != nil {
return err
Expand All @@ -84,10 +100,32 @@ func UpsertConfigToKeyring(creds []byte) error {
return err
}

// RemoveConfigFromKeyring will remove the credentials from the first priority OS secure store.
//
// Note: CGO_ENABLED=1 is required for OSX Keychain and darwin builds
func RemoveConfigFromKeyring() error {
if err := validateBackends(); err != nil {
return err
}

ring, err := keyring.Open(getKeyringConfig())
if err != nil {
return err
}

err = ring.Remove(ItemKey)

return err
}

// GetConfigFromKeyring will retrieve the credentials from the first priority OS secure store.
//
// Note: CGO_ENABLED=1 is required for OSX Keychain and darwin builds
func GetConfigFromKeyring() ([]byte, error) {
if err := validateBackends(); err != nil {
return nil, err
}

credentials := []byte("")

ring, err := keyring.Open(getKeyringConfig())
Expand Down Expand Up @@ -118,6 +156,14 @@ func GetConfigFromKeyring() ([]byte, error) {

}

// Validates that at least one backend is available
func validateBackends() error {
if len(AvailableBackends()) == 0 {
return ErrNoBackendsAvailable
}
return nil
}

// Compresses credential bytes to help ensure all OS secure stores can store the data.
// Windows Credential Manager has a 2500 byte limit.
func compressConfig(creds []byte) ([]byte, error) {
Expand Down
18 changes: 15 additions & 3 deletions examples/secure_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,26 @@ func main() {
config := []byte("mybytestringagain")

// Upsert to keyring
securestore.UpsertConfigToKeyring(config)
err = securestore.UpsertConfigToKeyring(config)
if err != nil {
fmt.Fprintf(os.Stderr, "Error upserting to keyring: %v", err)
os.Exit(1)
}

// Upsert again to keyring
config = []byte(token)
securestore.UpsertConfigToKeyring(config)
err = securestore.UpsertConfigToKeyring(config)
if err != nil {
fmt.Fprintf(os.Stderr, "Error upserting to keyring: %v", err)
os.Exit(1)
}

// Read bytes back from Keyring
readVal, _ := securestore.GetConfigFromKeyring()
readVal, err := securestore.GetConfigFromKeyring()
if err != nil {
fmt.Fprintf(os.Stderr, "Error reading from keyring: %v", err)
os.Exit(1)
}
// Should be a token
fmt.Printf("Read from keyring: %s\n", string(readVal))
}

0 comments on commit f7ad280

Please sign in to comment.