backport of commit 1484253e0ba27695d141b6ecea54eeca1da42e35 (#24408)
Co-authored-by: Austin Gebauer <34121980+austingebauer@users.noreply.github.com>
This commit is contained in:
parent
afc925b359
commit
8cf459b7f0
@ -643,6 +643,7 @@ func (i *IdentityStore) initialize(ctx context.Context, req *logical.Initializat
|
||||
}
|
||||
|
||||
if err := i.storeOIDCDefaultResources(ctx, req.Storage); err != nil {
|
||||
i.logger.Error("failed to write OIDC default resources to storage", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -108,6 +108,7 @@ var errNilNamespace = errors.New("nil namespace in oidc cache request")
|
||||
const (
|
||||
issuerPath = "identity/oidc"
|
||||
oidcTokensPrefix = "oidc_tokens/"
|
||||
namedKeyCachePrefix = "namedKeys/"
|
||||
oidcConfigStorageKey = oidcTokensPrefix + "config/"
|
||||
namedKeyConfigPath = oidcTokensPrefix + "named_keys/"
|
||||
publicKeysConfigPath = oidcTokensPrefix + "public_keys/"
|
||||
@ -983,7 +984,7 @@ func (i *IdentityStore) getNamedKey(ctx context.Context, s logical.Storage, name
|
||||
}
|
||||
|
||||
// Attempt to get the key from the cache
|
||||
keyRaw, found, err := i.oidcCache.Get(ns, "namedKeys/"+name)
|
||||
keyRaw, found, err := i.oidcCache.Get(ns, namedKeyCachePrefix+name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1005,7 +1006,7 @@ func (i *IdentityStore) getNamedKey(ctx context.Context, s logical.Storage, name
|
||||
}
|
||||
|
||||
// Cache the key
|
||||
if err := i.oidcCache.SetDefault(ns, "namedKeys/"+name, &key); err != nil {
|
||||
if err := i.oidcCache.SetDefault(ns, namedKeyCachePrefix+name, &key); err != nil {
|
||||
i.logger.Warn("failed to cache key", "error", err)
|
||||
}
|
||||
|
||||
@ -1176,6 +1177,12 @@ func (i *IdentityStore) pathOIDCCreateUpdateRole(ctx context.Context, req *logic
|
||||
return logical.ErrorResponse("the key parameter is required"), nil
|
||||
}
|
||||
|
||||
if role.Key == defaultKeyName {
|
||||
if err := i.lazyGenerateDefaultKey(ctx, req.Storage); err != nil {
|
||||
return nil, fmt.Errorf("failed to generate default key: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if template, ok := d.GetOk("template"); ok {
|
||||
role.Template = template.(string)
|
||||
} else if req.Operation == logical.CreateOperation {
|
||||
|
@ -1120,6 +1120,12 @@ func (i *IdentityStore) pathOIDCCreateUpdateClient(ctx context.Context, req *log
|
||||
return logical.ErrorResponse("key %q does not exist", client.Key), nil
|
||||
}
|
||||
|
||||
if client.Key == defaultKeyName {
|
||||
if err := i.lazyGenerateDefaultKey(ctx, req.Storage); err != nil {
|
||||
return nil, fmt.Errorf("failed to generate default key: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if idTokenTTLRaw, ok := d.GetOk("id_token_ttl"); ok {
|
||||
client.IDTokenTTL = time.Duration(idTokenTTLRaw.(int)) * time.Second
|
||||
} else if req.Operation == logical.CreateOperation {
|
||||
@ -2536,34 +2542,8 @@ func (i *IdentityStore) storeOIDCDefaultResources(ctx context.Context, view logi
|
||||
i.Logger().Debug("wrote OIDC default provider")
|
||||
}
|
||||
|
||||
// Store the default key
|
||||
storageKey = namedKeyConfigPath + defaultKeyName
|
||||
entry, err = view.Get(ctx, storageKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if entry == nil {
|
||||
defaultKey := defaultOIDCKey()
|
||||
|
||||
// Generate initial key material for current and next keys
|
||||
err = defaultKey.generateAndSetKey(ctx, i.Logger(), view)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = defaultKey.generateAndSetNextKey(ctx, i.Logger(), view)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Store the entry
|
||||
entry, err := logical.StorageEntryJSON(storageKey, defaultKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := view.Put(ctx, entry); err != nil {
|
||||
return err
|
||||
}
|
||||
i.Logger().Debug("wrote OIDC default key")
|
||||
if _, err := i.ensureDefaultKey(ctx, view); err != nil {
|
||||
return fmt.Errorf("error writing default key to storage: %w", err)
|
||||
}
|
||||
|
||||
// Store the allow all assignment
|
||||
@ -2586,6 +2566,71 @@ func (i *IdentityStore) storeOIDCDefaultResources(ctx context.Context, view logi
|
||||
return nil
|
||||
}
|
||||
|
||||
// ensureDefaultKey ensures that the OIDC default key is written to storage. If no
|
||||
// error is returned, callers can be sure that it exists in storage. Note that it
|
||||
// only writes the key's configuration to storage and does not generate key material
|
||||
// for its current and next keys.
|
||||
func (i *IdentityStore) ensureDefaultKey(ctx context.Context, storage logical.Storage) (*namedKey, error) {
|
||||
key, err := i.getNamedKey(ctx, storage, defaultKeyName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if key != nil {
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// The default key doesn't exist. Write it to storage.
|
||||
defaultKey := defaultOIDCKey()
|
||||
entry, err := logical.StorageEntryJSON(namedKeyConfigPath+defaultKeyName, defaultKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := storage.Put(ctx, entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
i.Logger().Debug("wrote OIDC default key")
|
||||
return &defaultKey, nil
|
||||
}
|
||||
|
||||
// lazyGenerateDefaultKey generates key material for the OIDC default key's current and
|
||||
// next key if it hasn't already been generated. Must be called with the oidcLock write
|
||||
// lock held.
|
||||
func (i *IdentityStore) lazyGenerateDefaultKey(ctx context.Context, storage logical.Storage) error {
|
||||
ns, err := namespace.FromContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defaultKey, err := i.ensureDefaultKey(ctx, storage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if defaultKey.SigningKey == nil {
|
||||
if err := defaultKey.generateAndSetKey(ctx, i.Logger(), storage); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := defaultKey.generateAndSetNextKey(ctx, i.Logger(), storage); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := i.oidcCache.Delete(ns, namedKeyCachePrefix+defaultKeyName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
entry, err := logical.StorageEntryJSON(namedKeyConfigPath+defaultKeyName, defaultKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := storage.Put(ctx, entry); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *IdentityStore) loadOIDCClients(ctx context.Context) error {
|
||||
i.logger.Debug("identity loading OIDC clients")
|
||||
|
||||
|
@ -1055,10 +1055,11 @@ func TestOIDC_PeriodicFunc(t *testing.T) {
|
||||
setSigningKey: true,
|
||||
setNextSigningKey: true,
|
||||
testCases: []testCase{
|
||||
// Each cycle results in a key going in/out of its verification_ttl period
|
||||
{1, 2, 2},
|
||||
{2, 2, 4},
|
||||
{3, 2, 4},
|
||||
{4, 2, 4},
|
||||
{2, 3, 3},
|
||||
{3, 2, 2},
|
||||
{4, 3, 3},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1067,8 +1068,11 @@ func TestOIDC_PeriodicFunc(t *testing.T) {
|
||||
setSigningKey: false,
|
||||
setNextSigningKey: true,
|
||||
testCases: []testCase{
|
||||
{1, 1, 2},
|
||||
{2, 2, 4},
|
||||
{1, 1, 1},
|
||||
|
||||
// key counts jump from 1 to 2 because the next signing key becomes
|
||||
// the signing key, and no key is in its verification_ttl period
|
||||
{2, 2, 2},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1077,8 +1081,11 @@ func TestOIDC_PeriodicFunc(t *testing.T) {
|
||||
setSigningKey: true,
|
||||
setNextSigningKey: false,
|
||||
testCases: []testCase{
|
||||
{1, 1, 2},
|
||||
{2, 2, 4},
|
||||
{1, 1, 1},
|
||||
|
||||
// key counts jump from 1 to 3 because the original signing key is
|
||||
// still published and within its verification_ttl period
|
||||
{2, 3, 3},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1087,8 +1094,8 @@ func TestOIDC_PeriodicFunc(t *testing.T) {
|
||||
setSigningKey: false,
|
||||
setNextSigningKey: false,
|
||||
testCases: []testCase{
|
||||
{1, 0, 2},
|
||||
{2, 2, 4},
|
||||
{1, 0, 0},
|
||||
{2, 2, 2},
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -1154,7 +1161,7 @@ func TestOIDC_PeriodicFunc(t *testing.T) {
|
||||
expectedKeyCount := testSet.testCases[i].numKeys
|
||||
namedKeySamples[i].DecodeJSON(&testSet.namedKey)
|
||||
actualKeyRingLen := len(testSet.namedKey.KeyRing)
|
||||
if actualKeyRingLen < expectedKeyCount {
|
||||
if actualKeyRingLen != expectedKeyCount {
|
||||
t.Errorf(
|
||||
"For key: %s at cycle: %d expected namedKey's KeyRing to be at least of length %d but was: %d",
|
||||
testSet.namedKey.name,
|
||||
@ -1165,7 +1172,7 @@ func TestOIDC_PeriodicFunc(t *testing.T) {
|
||||
}
|
||||
expectedPublicKeyCount := testSet.testCases[i].numPublicKeys
|
||||
actualPubKeysLen := len(publicKeysSamples[i])
|
||||
if actualPubKeysLen < expectedPublicKeyCount {
|
||||
if actualPubKeysLen != expectedPublicKeyCount {
|
||||
t.Errorf(
|
||||
"For key: %s at cycle: %d expected public keys to be at least of length %d but was: %d",
|
||||
testSet.namedKey.name,
|
||||
|
Loading…
Reference in New Issue
Block a user