1package logical 2 3import ( 4 "fmt" 5 "io" 6 "strings" 7 "time" 8) 9 10// RequestWrapInfo is a struct that stores information about desired response 11// and seal wrapping behavior 12type RequestWrapInfo struct { 13 // Setting to non-zero specifies that the response should be wrapped. 14 // Specifies the desired TTL of the wrapping token. 15 TTL time.Duration `json:"ttl" structs:"ttl" mapstructure:"ttl" sentinel:""` 16 17 // The format to use for the wrapped response; if not specified it's a bare 18 // token 19 Format string `json:"format" structs:"format" mapstructure:"format" sentinel:""` 20 21 // A flag to conforming backends that data for a given request should be 22 // seal wrapped 23 SealWrap bool `json:"seal_wrap" structs:"seal_wrap" mapstructure:"seal_wrap" sentinel:""` 24} 25 26func (r *RequestWrapInfo) SentinelGet(key string) (interface{}, error) { 27 if r == nil { 28 return nil, nil 29 } 30 switch key { 31 case "ttl": 32 return r.TTL, nil 33 case "ttl_seconds": 34 return int64(r.TTL.Seconds()), nil 35 } 36 37 return nil, nil 38} 39 40func (r *RequestWrapInfo) SentinelKeys() []string { 41 return []string{ 42 "ttl", 43 "ttl_seconds", 44 } 45} 46 47type ClientTokenSource uint32 48 49const ( 50 NoClientToken ClientTokenSource = iota 51 ClientTokenFromVaultHeader 52 ClientTokenFromAuthzHeader 53) 54 55// Request is a struct that stores the parameters and context of a request 56// being made to Vault. It is used to abstract the details of the higher level 57// request protocol from the handlers. 58// 59// Note: Many of these have Sentinel disabled because they are values populated 60// by the router after policy checks; the token namespace would be the right 61// place to access them via Sentinel 62type Request struct { 63 // Id is the uuid associated with each request 64 ID string `json:"id" structs:"id" mapstructure:"id" sentinel:""` 65 66 // If set, the name given to the replication secondary where this request 67 // originated 68 ReplicationCluster string `json:"replication_cluster" structs:"replication_cluster" mapstructure:"replication_cluster" sentinel:""` 69 70 // Operation is the requested operation type 71 Operation Operation `json:"operation" structs:"operation" mapstructure:"operation"` 72 73 // Path is the part of the request path not consumed by the 74 // routing. As an example, if the original request path is "prod/aws/foo" 75 // and the AWS logical backend is mounted at "prod/aws/", then the 76 // final path is "foo" since the mount prefix is trimmed. 77 Path string `json:"path" structs:"path" mapstructure:"path" sentinel:""` 78 79 // Request data is an opaque map that must have string keys. 80 Data map[string]interface{} `json:"map" structs:"data" mapstructure:"data"` 81 82 // Storage can be used to durably store and retrieve state. 83 Storage Storage `json:"-" sentinel:""` 84 85 // Secret will be non-nil only for Revoke and Renew operations 86 // to represent the secret that was returned prior. 87 Secret *Secret `json:"secret" structs:"secret" mapstructure:"secret" sentinel:""` 88 89 // Auth will be non-nil only for Renew operations 90 // to represent the auth that was returned prior. 91 Auth *Auth `json:"auth" structs:"auth" mapstructure:"auth" sentinel:""` 92 93 // Headers will contain the http headers from the request. This value will 94 // be used in the audit broker to ensure we are auditing only the allowed 95 // headers. 96 Headers map[string][]string `json:"headers" structs:"headers" mapstructure:"headers" sentinel:""` 97 98 // Connection will be non-nil only for credential providers to 99 // inspect the connection information and potentially use it for 100 // authentication/protection. 101 Connection *Connection `json:"connection" structs:"connection" mapstructure:"connection"` 102 103 // ClientToken is provided to the core so that the identity 104 // can be verified and ACLs applied. This value is passed 105 // through to the logical backends but after being salted and 106 // hashed. 107 ClientToken string `json:"client_token" structs:"client_token" mapstructure:"client_token" sentinel:""` 108 109 // ClientTokenAccessor is provided to the core so that the it can get 110 // logged as part of request audit logging. 111 ClientTokenAccessor string `json:"client_token_accessor" structs:"client_token_accessor" mapstructure:"client_token_accessor" sentinel:""` 112 113 // DisplayName is provided to the logical backend to help associate 114 // dynamic secrets with the source entity. This is not a sensitive 115 // name, but is useful for operators. 116 DisplayName string `json:"display_name" structs:"display_name" mapstructure:"display_name" sentinel:""` 117 118 // MountPoint is provided so that a logical backend can generate 119 // paths relative to itself. The `Path` is effectively the client 120 // request path with the MountPoint trimmed off. 121 MountPoint string `json:"mount_point" structs:"mount_point" mapstructure:"mount_point" sentinel:""` 122 123 // MountType is provided so that a logical backend can make decisions 124 // based on the specific mount type (e.g., if a mount type has different 125 // aliases, generating different defaults depending on the alias) 126 MountType string `json:"mount_type" structs:"mount_type" mapstructure:"mount_type" sentinel:""` 127 128 // MountAccessor is provided so that identities returned by the authentication 129 // backends can be tied to the mount it belongs to. 130 MountAccessor string `json:"mount_accessor" structs:"mount_accessor" mapstructure:"mount_accessor" sentinel:""` 131 132 // WrapInfo contains requested response wrapping parameters 133 WrapInfo *RequestWrapInfo `json:"wrap_info" structs:"wrap_info" mapstructure:"wrap_info" sentinel:""` 134 135 // ClientTokenRemainingUses represents the allowed number of uses left on the 136 // token supplied 137 ClientTokenRemainingUses int `json:"client_token_remaining_uses" structs:"client_token_remaining_uses" mapstructure:"client_token_remaining_uses"` 138 139 // EntityID is the identity of the caller extracted out of the token used 140 // to make this request 141 EntityID string `json:"entity_id" structs:"entity_id" mapstructure:"entity_id" sentinel:""` 142 143 // PolicyOverride indicates that the requestor wishes to override 144 // soft-mandatory Sentinel policies 145 PolicyOverride bool `json:"policy_override" structs:"policy_override" mapstructure:"policy_override"` 146 147 // Whether the request is unauthenticated, as in, had no client token 148 // attached. Useful in some situations where the client token is not made 149 // accessible. 150 Unauthenticated bool `json:"unauthenticated" structs:"unauthenticated" mapstructure:"unauthenticated"` 151 152 // MFACreds holds the parsed MFA information supplied over the API as part of 153 // X-Vault-MFA header 154 MFACreds MFACreds `json:"mfa_creds" structs:"mfa_creds" mapstructure:"mfa_creds" sentinel:""` 155 156 // Cached token entry. This avoids another lookup in request handling when 157 // we've already looked it up at http handling time. Note that this token 158 // has not been "used", as in it will not properly take into account use 159 // count limitations. As a result this field should only ever be used for 160 // transport to a function that would otherwise do a lookup and then 161 // properly use the token. 162 tokenEntry *TokenEntry 163 164 // For replication, contains the last WAL on the remote side after handling 165 // the request, used for best-effort avoidance of stale read-after-write 166 lastRemoteWAL uint64 167 168 // ControlGroup holds the authorizations that have happened on this 169 // request 170 ControlGroup *ControlGroup `json:"control_group" structs:"control_group" mapstructure:"control_group" sentinel:""` 171 172 // ClientTokenSource tells us where the client token was sourced from, so 173 // we can delete it before sending off to plugins 174 ClientTokenSource ClientTokenSource 175 176 // RequestReader if set can be used to read the full request body from the 177 // http request that generated this logical.Request object. 178 RequestReader io.ReadCloser `json:"-" sentinel:""` 179 180 // ResponseWriter if set can be used to stream a response value to the http 181 // request that generated this logical.Request object. 182 ResponseWriter *HTTPResponseWriter `json:"-" sentinel:""` 183} 184 185// Get returns a data field and guards for nil Data 186func (r *Request) Get(key string) interface{} { 187 if r.Data == nil { 188 return nil 189 } 190 return r.Data[key] 191} 192 193// GetString returns a data field as a string 194func (r *Request) GetString(key string) string { 195 raw := r.Get(key) 196 s, _ := raw.(string) 197 return s 198} 199 200func (r *Request) GoString() string { 201 return fmt.Sprintf("*%#v", *r) 202} 203 204func (r *Request) SentinelGet(key string) (interface{}, error) { 205 switch key { 206 case "path": 207 // Sanitize it here so that it's consistent in policies 208 return strings.TrimPrefix(r.Path, "/"), nil 209 210 case "wrapping", "wrap_info": 211 // If the pointer is nil accessing the wrap info is considered 212 // "undefined" so this allows us to instead discover a TTL of zero 213 if r.WrapInfo == nil { 214 return &RequestWrapInfo{}, nil 215 } 216 return r.WrapInfo, nil 217 } 218 219 return nil, nil 220} 221 222func (r *Request) SentinelKeys() []string { 223 return []string{ 224 "path", 225 "wrapping", 226 "wrap_info", 227 } 228} 229 230func (r *Request) LastRemoteWAL() uint64 { 231 return r.lastRemoteWAL 232} 233 234func (r *Request) SetLastRemoteWAL(last uint64) { 235 r.lastRemoteWAL = last 236} 237 238func (r *Request) TokenEntry() *TokenEntry { 239 return r.tokenEntry 240} 241 242func (r *Request) SetTokenEntry(te *TokenEntry) { 243 r.tokenEntry = te 244} 245 246// RenewRequest creates the structure of the renew request. 247func RenewRequest(path string, secret *Secret, data map[string]interface{}) *Request { 248 return &Request{ 249 Operation: RenewOperation, 250 Path: path, 251 Data: data, 252 Secret: secret, 253 } 254} 255 256// RenewAuthRequest creates the structure of the renew request for an auth. 257func RenewAuthRequest(path string, auth *Auth, data map[string]interface{}) *Request { 258 return &Request{ 259 Operation: RenewOperation, 260 Path: path, 261 Data: data, 262 Auth: auth, 263 } 264} 265 266// RevokeRequest creates the structure of the revoke request. 267func RevokeRequest(path string, secret *Secret, data map[string]interface{}) *Request { 268 return &Request{ 269 Operation: RevokeOperation, 270 Path: path, 271 Data: data, 272 Secret: secret, 273 } 274} 275 276// RollbackRequest creates the structure of the revoke request. 277func RollbackRequest(path string) *Request { 278 return &Request{ 279 Operation: RollbackOperation, 280 Path: path, 281 Data: make(map[string]interface{}), 282 } 283} 284 285// Operation is an enum that is used to specify the type 286// of request being made 287type Operation string 288 289const ( 290 // The operations below are called per path 291 CreateOperation Operation = "create" 292 ReadOperation = "read" 293 UpdateOperation = "update" 294 DeleteOperation = "delete" 295 ListOperation = "list" 296 HelpOperation = "help" 297 AliasLookaheadOperation = "alias-lookahead" 298 299 // The operations below are called globally, the path is less relevant. 300 RevokeOperation Operation = "revoke" 301 RenewOperation = "renew" 302 RollbackOperation = "rollback" 303) 304 305type MFACreds map[string][]string 306 307// InitializationRequest stores the parameters and context of an Initialize() 308// call being made to a logical.Backend. 309type InitializationRequest struct { 310 311 // Storage can be used to durably store and retrieve state. 312 Storage Storage 313} 314