1package awsauth
2
3import (
4	"context"
5	"fmt"
6
7	"github.com/hashicorp/vault/sdk/framework"
8	"github.com/hashicorp/vault/sdk/logical"
9)
10
11const (
12	identityWhitelistConfigPath = "config/tidy/identity-whitelist"
13)
14
15func pathConfigTidyIdentityWhitelist(b *backend) *framework.Path {
16	return &framework.Path{
17		Pattern: fmt.Sprintf("%s$", identityWhitelistConfigPath),
18		Fields: map[string]*framework.FieldSchema{
19			"safety_buffer": &framework.FieldSchema{
20				Type:    framework.TypeDurationSecond,
21				Default: 259200, //72h
22				Description: `The amount of extra time that must have passed beyond the identity's
23expiration, before it is removed from the backend storage.`,
24			},
25			"disable_periodic_tidy": &framework.FieldSchema{
26				Type:        framework.TypeBool,
27				Default:     false,
28				Description: "If set to 'true', disables the periodic tidying of the 'identity-whitelist/<instance_id>' entries.",
29			},
30		},
31
32		ExistenceCheck: b.pathConfigTidyIdentityWhitelistExistenceCheck,
33
34		Callbacks: map[logical.Operation]framework.OperationFunc{
35			logical.CreateOperation: b.pathConfigTidyIdentityWhitelistCreateUpdate,
36			logical.UpdateOperation: b.pathConfigTidyIdentityWhitelistCreateUpdate,
37			logical.ReadOperation:   b.pathConfigTidyIdentityWhitelistRead,
38			logical.DeleteOperation: b.pathConfigTidyIdentityWhitelistDelete,
39		},
40
41		HelpSynopsis:    pathConfigTidyIdentityWhitelistHelpSyn,
42		HelpDescription: pathConfigTidyIdentityWhitelistHelpDesc,
43	}
44}
45
46func (b *backend) pathConfigTidyIdentityWhitelistExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) {
47	entry, err := b.lockedConfigTidyIdentities(ctx, req.Storage)
48	if err != nil {
49		return false, err
50	}
51	return entry != nil, nil
52}
53
54func (b *backend) lockedConfigTidyIdentities(ctx context.Context, s logical.Storage) (*tidyWhitelistIdentityConfig, error) {
55	b.configMutex.RLock()
56	defer b.configMutex.RUnlock()
57
58	return b.nonLockedConfigTidyIdentities(ctx, s)
59}
60
61func (b *backend) nonLockedConfigTidyIdentities(ctx context.Context, s logical.Storage) (*tidyWhitelistIdentityConfig, error) {
62	entry, err := s.Get(ctx, identityWhitelistConfigPath)
63	if err != nil {
64		return nil, err
65	}
66	if entry == nil {
67		return nil, nil
68	}
69
70	var result tidyWhitelistIdentityConfig
71	if err := entry.DecodeJSON(&result); err != nil {
72		return nil, err
73	}
74	return &result, nil
75}
76
77func (b *backend) pathConfigTidyIdentityWhitelistCreateUpdate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
78	b.configMutex.Lock()
79	defer b.configMutex.Unlock()
80
81	configEntry, err := b.nonLockedConfigTidyIdentities(ctx, req.Storage)
82	if err != nil {
83		return nil, err
84	}
85	if configEntry == nil {
86		configEntry = &tidyWhitelistIdentityConfig{}
87	}
88
89	safetyBufferInt, ok := data.GetOk("safety_buffer")
90	if ok {
91		configEntry.SafetyBuffer = safetyBufferInt.(int)
92	} else if req.Operation == logical.CreateOperation {
93		configEntry.SafetyBuffer = data.Get("safety_buffer").(int)
94	}
95
96	disablePeriodicTidyBool, ok := data.GetOk("disable_periodic_tidy")
97	if ok {
98		configEntry.DisablePeriodicTidy = disablePeriodicTidyBool.(bool)
99	} else if req.Operation == logical.CreateOperation {
100		configEntry.DisablePeriodicTidy = data.Get("disable_periodic_tidy").(bool)
101	}
102
103	entry, err := logical.StorageEntryJSON(identityWhitelistConfigPath, configEntry)
104	if err != nil {
105		return nil, err
106	}
107
108	if err := req.Storage.Put(ctx, entry); err != nil {
109		return nil, err
110	}
111
112	return nil, nil
113}
114
115func (b *backend) pathConfigTidyIdentityWhitelistRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
116	clientConfig, err := b.lockedConfigTidyIdentities(ctx, req.Storage)
117	if err != nil {
118		return nil, err
119	}
120	if clientConfig == nil {
121		return nil, nil
122	}
123
124	return &logical.Response{
125		Data: map[string]interface{}{
126			"safety_buffer":         clientConfig.SafetyBuffer,
127			"disable_periodic_tidy": clientConfig.DisablePeriodicTidy,
128		},
129	}, nil
130}
131
132func (b *backend) pathConfigTidyIdentityWhitelistDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
133	b.configMutex.Lock()
134	defer b.configMutex.Unlock()
135
136	return nil, req.Storage.Delete(ctx, identityWhitelistConfigPath)
137}
138
139type tidyWhitelistIdentityConfig struct {
140	SafetyBuffer        int  `json:"safety_buffer"`
141	DisablePeriodicTidy bool `json:"disable_periodic_tidy"`
142}
143
144const pathConfigTidyIdentityWhitelistHelpSyn = `
145Configures the periodic tidying operation of the whitelisted identity entries.
146`
147const pathConfigTidyIdentityWhitelistHelpDesc = `
148By default, the expired entries in the whitelist will be attempted to be removed
149periodically. This operation will look for expired items in the list and purges them.
150However, there is a safety buffer duration (defaults to 72h), purges the entries
151only if they have been persisting this duration, past its expiration time.
152`
153