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