Added OpenAPI response structures for sys endpoints (#18515)

* added response objects to all of the endpoints laid out by the ticket linked

* added changelog file and updated based on review

* added the required bool to the correct fields

* Update vault/logical_system_paths.go

Co-authored-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* Update vault/logical_system_paths.go

Co-authored-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* Update vault/logical_system_paths.go

Co-authored-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* Update vault/logical_system_paths.go

Co-authored-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* Update vault/logical_system_paths.go

Co-authored-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* Update vault/logical_system_paths.go

Co-authored-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* Update vault/logical_system_paths.go

Co-authored-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* updated based on review

* Update vault/logical_system_paths.go

Co-authored-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* Update vault/logical_system_paths.go

Co-authored-by: Daniel Huckins <dhuckins@users.noreply.github.com>

* updated based on review and added test cases for validating response structures

* fix copy pasta issues breaking tests

* Update vault/logical_system_paths.go

Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com>

* fix test failures

* fixed issue with refrencing the wrong req var name

* fixed another test case and double checked the rest

* updated based on review

* updated in all locations

* Update vault/logical_system_paths.go

Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com>

* Update vault/logical_system_paths.go

Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com>

* fixed my brain fart

* Update vault/logical_system_paths.go

Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com>

* address fmt error

---------

Co-authored-by: lursu <leland.ursu@hashicorp.com>
Co-authored-by: Daniel Huckins <dhuckins@users.noreply.github.com>
Co-authored-by: Anton Averchenkov <84287187+averche@users.noreply.github.com>
This commit is contained in:
Leland Ursu 2023-02-15 15:00:06 -05:00 committed by GitHub
parent 7fde5ecb83
commit 6425130605
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 902 additions and 83 deletions

3
changelog/18515.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:improvement
openapi: Add openapi response definitions to vault/logical_system_paths.go defined endpoints.
```

View File

@ -301,15 +301,30 @@ func (b *SystemBackend) configPaths() []*framework.Path {
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: &framework.PathOperation{ logical.ReadOperation: &framework.PathOperation{
Callback: b.handleLoggersRead, Callback: b.handleLoggersRead,
Summary: "Read the log level for all existing loggers.", Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
}},
},
Summary: "Read the log level for all existing loggers.",
}, },
logical.UpdateOperation: &framework.PathOperation{ logical.UpdateOperation: &framework.PathOperation{
Callback: b.handleLoggersWrite, Callback: b.handleLoggersWrite,
Summary: "Modify the log level for all existing loggers.", Responses: map[int][]framework.Response{
http.StatusNoContent: {{
Description: "OK",
}},
},
Summary: "Modify the log level for all existing loggers.",
}, },
logical.DeleteOperation: &framework.PathOperation{ logical.DeleteOperation: &framework.PathOperation{
Callback: b.handleLoggersDelete, Callback: b.handleLoggersDelete,
Summary: "Revert the all loggers to use log level provided in config.", Responses: map[int][]framework.Response{
http.StatusNoContent: {{
Description: "OK",
}},
},
Summary: "Revert the all loggers to use log level provided in config.",
}, },
}, },
}, },
@ -329,15 +344,30 @@ func (b *SystemBackend) configPaths() []*framework.Path {
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: &framework.PathOperation{ logical.ReadOperation: &framework.PathOperation{
Callback: b.handleLoggersByNameRead, Callback: b.handleLoggersByNameRead,
Summary: "Read the log level for a single logger.", Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
}},
},
Summary: "Read the log level for a single logger.",
}, },
logical.UpdateOperation: &framework.PathOperation{ logical.UpdateOperation: &framework.PathOperation{
Callback: b.handleLoggersByNameWrite, Callback: b.handleLoggersByNameWrite,
Summary: "Modify the log level of a single logger.", Responses: map[int][]framework.Response{
http.StatusNoContent: {{
Description: "OK",
}},
},
Summary: "Modify the log level of a single logger.",
}, },
logical.DeleteOperation: &framework.PathOperation{ logical.DeleteOperation: &framework.PathOperation{
Callback: b.handleLoggersByNameDelete, Callback: b.handleLoggersByNameDelete,
Summary: "Revert a single logger to use log level provided in config.", Responses: map[int][]framework.Response{
http.StatusNoContent: {{
Description: "OK",
}},
},
Summary: "Revert a single logger to use log level provided in config.",
}, },
}, },
}, },
@ -841,15 +871,66 @@ func (b *SystemBackend) pluginsCatalogCRUDPath() *framework.Path {
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: &framework.PathOperation{ logical.UpdateOperation: &framework.PathOperation{
Callback: b.handlePluginCatalogUpdate, Callback: b.handlePluginCatalogUpdate,
Summary: "Register a new plugin, or updates an existing one with the supplied name.", Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
}},
},
Summary: "Register a new plugin, or updates an existing one with the supplied name.",
}, },
logical.DeleteOperation: &framework.PathOperation{ logical.DeleteOperation: &framework.PathOperation{
Callback: b.handlePluginCatalogDelete, Callback: b.handlePluginCatalogDelete,
Summary: "Remove the plugin with the given name.", Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{},
}},
},
Summary: "Remove the plugin with the given name.",
}, },
logical.ReadOperation: &framework.PathOperation{ logical.ReadOperation: &framework.PathOperation{
Callback: b.handlePluginCatalogRead, Callback: b.handlePluginCatalogRead,
Summary: "Return the configuration data for the plugin with the given name.", Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"name": {
Type: framework.TypeString,
Description: strings.TrimSpace(sysHelp["plugin-catalog_name"][0]),
Required: true,
},
"sha256": {
Type: framework.TypeString,
Description: strings.TrimSpace(sysHelp["plugin-catalog_sha-256"][0]),
Required: true,
},
"command": {
Type: framework.TypeString,
Description: strings.TrimSpace(sysHelp["plugin-catalog_command"][0]),
Required: true,
},
"args": {
Type: framework.TypeStringSlice,
Description: strings.TrimSpace(sysHelp["plugin-catalog_args"][0]),
Required: true,
},
"version": {
Type: framework.TypeString,
Description: strings.TrimSpace(sysHelp["plugin-catalog_version"][0]),
Required: true,
},
"builtin": {
Type: framework.TypeBool,
Required: true,
},
"deprecation_status": {
Type: framework.TypeString,
Required: false,
},
},
}},
},
Summary: "Return the configuration data for the plugin with the given name.",
}, },
}, },
@ -873,7 +954,19 @@ func (b *SystemBackend) pluginsCatalogListPaths() []*framework.Path {
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ListOperation: &framework.PathOperation{ logical.ListOperation: &framework.PathOperation{
Callback: b.handlePluginCatalogTypedList, Callback: b.handlePluginCatalogTypedList,
Summary: "List the plugins in the catalog.", Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"keys": {
Type: framework.TypeStringSlice,
Description: "List of plugin names in the catalog",
Required: true,
},
},
}},
},
Summary: "List the plugins in the catalog.",
}, },
}, },
@ -883,8 +976,21 @@ func (b *SystemBackend) pluginsCatalogListPaths() []*framework.Path {
{ {
Pattern: "plugins/catalog/?$", Pattern: "plugins/catalog/?$",
Callbacks: map[logical.Operation]framework.OperationFunc{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: b.handlePluginCatalogUntypedList, logical.ReadOperation: &framework.PathOperation{
Callback: b.handlePluginCatalogUntypedList,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"detailed": {
Type: framework.TypeMap,
Required: false,
},
},
}},
},
},
}, },
HelpSynopsis: strings.TrimSpace(sysHelp["plugin-catalog-list-all"][0]), HelpSynopsis: strings.TrimSpace(sysHelp["plugin-catalog-list-all"][0]),
@ -914,7 +1020,27 @@ func (b *SystemBackend) pluginsReloadPath() *framework.Path {
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: &framework.PathOperation{ logical.UpdateOperation: &framework.PathOperation{
Callback: b.handlePluginReloadUpdate, Callback: b.handlePluginReloadUpdate,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"reload_id": {
Type: framework.TypeString,
Required: true,
},
},
}},
http.StatusAccepted: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"reload_id": {
Type: framework.TypeString,
Required: true,
},
},
}},
},
Summary: "Reload mounted plugin backends.", Summary: "Reload mounted plugin backends.",
Description: "Either the plugin name (`plugin`) or the desired plugin backend mounts (`mounts`) must be provided, but not both. In the case that the plugin name is provided, all mounted paths that use that plugin backend will be reloaded. If (`scope`) is provided and is (`global`), the plugin(s) are reloaded globally.", Description: "Either the plugin name (`plugin`) or the desired plugin backend mounts (`mounts`) must be provided, but not both. In the case that the plugin name is provided, all mounted paths that use that plugin backend will be reloaded. If (`scope`) is provided and is (`global`), the plugin(s) are reloaded globally.",
}, },
@ -1246,7 +1372,18 @@ func (b *SystemBackend) leasePaths() []*framework.Path {
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ListOperation: &framework.PathOperation{ logical.ListOperation: &framework.PathOperation{
Callback: b.handleLeaseLookupList, Callback: b.handleLeaseLookupList,
Summary: "Returns a list of lease ids.", Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"keys": {
Type: framework.TypeCommaStringSlice,
Description: "A list of lease ids",
Required: false,
},
},
}},
},
}, },
}, },
@ -1267,7 +1404,43 @@ func (b *SystemBackend) leasePaths() []*framework.Path {
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: &framework.PathOperation{ logical.UpdateOperation: &framework.PathOperation{
Callback: b.handleLeaseLookup, Callback: b.handleLeaseLookup,
Summary: "Retrieve lease metadata.", Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"id": {
Type: framework.TypeString,
Description: "Lease id",
Required: true,
},
"issue_time": {
Type: framework.TypeTime,
Description: "Timestamp for the lease's issue time",
Required: true,
},
"renewable": {
Type: framework.TypeBool,
Description: "True if the lease is able to be renewed",
Required: true,
},
"expire_time": {
Type: framework.TypeTime,
Description: "Optional lease expiry time ",
Required: true,
},
"last_renewal": {
Type: framework.TypeTime,
Description: "Optional Timestamp of the last time the lease was renewed",
Required: true,
},
"ttl": {
Type: framework.TypeInt,
Description: "Time to Live set for the lease, returns 0 if unset",
Required: true,
},
},
}},
},
}, },
}, },
@ -1296,7 +1469,12 @@ func (b *SystemBackend) leasePaths() []*framework.Path {
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: &framework.PathOperation{ logical.UpdateOperation: &framework.PathOperation{
Callback: b.handleRenew, Callback: b.handleRenew,
Summary: "Renews a lease, requesting to extend the lease.", Responses: map[int][]framework.Response{
http.StatusNoContent: {{
Description: "OK",
}},
},
Summary: "Renews a lease, requesting to extend the lease.",
}, },
}, },
@ -1326,7 +1504,12 @@ func (b *SystemBackend) leasePaths() []*framework.Path {
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: &framework.PathOperation{ logical.UpdateOperation: &framework.PathOperation{
Callback: b.handleRevoke, Callback: b.handleRevoke,
Summary: "Revokes a lease immediately.", Responses: map[int][]framework.Response{
http.StatusNoContent: {{
Description: "OK",
}},
},
Summary: "Revokes a lease immediately.",
}, },
}, },
@ -1346,7 +1529,12 @@ func (b *SystemBackend) leasePaths() []*framework.Path {
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: &framework.PathOperation{ logical.UpdateOperation: &framework.PathOperation{
Callback: b.handleRevokeForce, Callback: b.handleRevokeForce,
Responses: map[int][]framework.Response{
http.StatusNoContent: {{
Description: "OK",
}},
},
Summary: "Revokes all secrets or tokens generated under a given prefix immediately", Summary: "Revokes all secrets or tokens generated under a given prefix immediately",
Description: "Unlike `/sys/leases/revoke-prefix`, this path ignores backend errors encountered during revocation. This is potentially very dangerous and should only be used in specific emergency situations where errors in the backend or the connected backend service prevent normal revocation.\n\nBy ignoring these errors, Vault abdicates responsibility for ensuring that the issued credentials or secrets are properly revoked and/or cleaned up. Access to this endpoint should be tightly controlled.", Description: "Unlike `/sys/leases/revoke-prefix`, this path ignores backend errors encountered during revocation. This is potentially very dangerous and should only be used in specific emergency situations where errors in the backend or the connected backend service prevent normal revocation.\n\nBy ignoring these errors, Vault abdicates responsibility for ensuring that the issued credentials or secrets are properly revoked and/or cleaned up. Access to this endpoint should be tightly controlled.",
}, },
@ -1374,7 +1562,12 @@ func (b *SystemBackend) leasePaths() []*framework.Path {
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: &framework.PathOperation{ logical.UpdateOperation: &framework.PathOperation{
Callback: b.handleRevokePrefix, Callback: b.handleRevokePrefix,
Summary: "Revokes all secrets (via a lease ID prefix) or tokens (via the tokens' path property) generated under a given prefix immediately.", Responses: map[int][]framework.Response{
http.StatusNoContent: {{
Description: "OK",
}},
},
Summary: "Revokes all secrets (via a lease ID prefix) or tokens (via the tokens' path property) generated under a given prefix immediately.",
}, },
}, },
@ -1385,8 +1578,16 @@ func (b *SystemBackend) leasePaths() []*framework.Path {
{ {
Pattern: "leases/tidy$", Pattern: "leases/tidy$",
Callbacks: map[logical.Operation]framework.OperationFunc{ Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: b.handleTidyLeases, logical.UpdateOperation: &framework.PathOperation{
Callback: b.handleTidyLeases,
Responses: map[int][]framework.Response{
http.StatusNoContent: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{},
}},
},
},
}, },
HelpSynopsis: strings.TrimSpace(sysHelp["tidy_leases"][0]), HelpSynopsis: strings.TrimSpace(sysHelp["tidy_leases"][0]),
@ -1408,9 +1609,28 @@ func (b *SystemBackend) leasePaths() []*framework.Path {
}, },
}, },
Callbacks: map[logical.Operation]framework.OperationFunc{ Operations: map[logical.Operation]framework.OperationHandler{
// currently only works for irrevocable leases with param: type=irrevocable logical.ReadOperation: &framework.PathOperation{
logical.ReadOperation: b.handleLeaseCount, // currently only works for irrevocable leases with param: type=irrevocable
Callback: b.handleLeaseCount,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"lease_count": {
Type: framework.TypeInt,
Description: "Number of matching leases",
Required: true,
},
"counts": {
Type: framework.TypeInt,
Description: "Number of matching leases per mount",
Required: true,
},
},
}},
},
},
}, },
HelpSynopsis: strings.TrimSpace(sysHelp["count-leases"][0]), HelpSynopsis: strings.TrimSpace(sysHelp["count-leases"][0]),
@ -1437,9 +1657,28 @@ func (b *SystemBackend) leasePaths() []*framework.Path {
}, },
}, },
Callbacks: map[logical.Operation]framework.OperationFunc{ Operations: map[logical.Operation]framework.OperationHandler{
// currently only works for irrevocable leases with param: type=irrevocable logical.ReadOperation: &framework.PathOperation{
logical.ReadOperation: b.handleLeaseList, // currently only works for irrevocable leases with param: type=irrevocable
Callback: b.handleLeaseList,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"lease_count": {
Type: framework.TypeInt,
Description: "Number of matching leases",
Required: true,
},
"counts": {
Type: framework.TypeInt,
Description: "Number of matching leases per mount",
Required: true,
},
},
}},
},
},
}, },
HelpSynopsis: strings.TrimSpace(sysHelp["list-leases"][0]), HelpSynopsis: strings.TrimSpace(sysHelp["list-leases"][0]),
@ -1505,8 +1744,15 @@ func (b *SystemBackend) metricsPath() *framework.Path {
Query: true, Query: true,
}, },
}, },
Callbacks: map[logical.Operation]framework.OperationFunc{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: b.handleMetrics, logical.ReadOperation: &framework.PathOperation{
Callback: b.handleMetrics,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
}},
},
},
}, },
HelpSynopsis: strings.TrimSpace(sysHelp["metrics"][0]), HelpSynopsis: strings.TrimSpace(sysHelp["metrics"][0]),
HelpDescription: strings.TrimSpace(sysHelp["metrics"][1]), HelpDescription: strings.TrimSpace(sysHelp["metrics"][1]),
@ -1529,8 +1775,15 @@ func (b *SystemBackend) monitorPath() *framework.Path {
Default: "standard", Default: "standard",
}, },
}, },
Callbacks: map[logical.Operation]framework.OperationFunc{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: b.handleMonitor, logical.ReadOperation: &framework.PathOperation{
Callback: b.handleMonitor,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
}},
},
},
}, },
HelpSynopsis: strings.TrimSpace(sysHelp["monitor"][0]), HelpSynopsis: strings.TrimSpace(sysHelp["monitor"][0]),
HelpDescription: strings.TrimSpace(sysHelp["monitor"][1]), HelpDescription: strings.TrimSpace(sysHelp["monitor"][1]),
@ -1721,9 +1974,41 @@ func (b *SystemBackend) policyPaths() []*framework.Path {
{ {
Pattern: "policy/?$", Pattern: "policy/?$",
Callbacks: map[logical.Operation]framework.OperationFunc{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: b.handlePoliciesList(PolicyTypeACL), logical.ReadOperation: &framework.PathOperation{
logical.ListOperation: b.handlePoliciesList(PolicyTypeACL), Callback: b.handlePoliciesList(PolicyTypeACL),
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"keys": {
Type: framework.TypeStringSlice,
Required: true,
},
"policies": {
Type: framework.TypeStringSlice,
},
},
}},
},
},
logical.ListOperation: &framework.PathOperation{
Callback: b.handlePoliciesList(PolicyTypeACL),
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"keys": {
Type: framework.TypeStringSlice,
Required: true,
},
"policies": {
Type: framework.TypeStringSlice,
},
},
}},
},
},
}, },
HelpSynopsis: strings.TrimSpace(sysHelp["policy-list"][0]), HelpSynopsis: strings.TrimSpace(sysHelp["policy-list"][0]),
@ -1752,15 +2037,46 @@ func (b *SystemBackend) policyPaths() []*framework.Path {
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: &framework.PathOperation{ logical.ReadOperation: &framework.PathOperation{
Callback: b.handlePoliciesRead(PolicyTypeACL), Callback: b.handlePoliciesRead(PolicyTypeACL),
Summary: "Retrieve the policy body for the named policy.", Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"name": {
Type: framework.TypeString,
Required: true,
},
"rules": {
Type: framework.TypeString,
Required: true,
},
"policy": {
Type: framework.TypeString,
Required: false,
},
},
}},
},
Summary: "Retrieve the policy body for the named policy.",
}, },
logical.UpdateOperation: &framework.PathOperation{ logical.UpdateOperation: &framework.PathOperation{
Callback: b.handlePoliciesSet(PolicyTypeACL), Callback: b.handlePoliciesSet(PolicyTypeACL),
Summary: "Add a new or update an existing policy.", Responses: map[int][]framework.Response{
http.StatusNoContent: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{},
}},
},
Summary: "Add a new or update an existing policy.",
}, },
logical.DeleteOperation: &framework.PathOperation{ logical.DeleteOperation: &framework.PathOperation{
Callback: b.handlePoliciesDelete(PolicyTypeACL), Callback: b.handlePoliciesDelete(PolicyTypeACL),
Summary: "Delete the policy with the given name.", Responses: map[int][]framework.Response{
http.StatusNoContent: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{},
}},
},
Summary: "Delete the policy with the given name.",
}, },
}, },
@ -1771,8 +2087,24 @@ func (b *SystemBackend) policyPaths() []*framework.Path {
{ {
Pattern: "policies/acl/?$", Pattern: "policies/acl/?$",
Callbacks: map[logical.Operation]framework.OperationFunc{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ListOperation: b.handlePoliciesList(PolicyTypeACL), logical.ListOperation: &framework.PathOperation{
Callback: b.handlePoliciesList(PolicyTypeACL),
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"keys": {
Type: framework.TypeStringSlice,
Required: true,
},
"policies": {
Type: framework.TypeStringSlice,
},
},
}},
},
},
}, },
HelpSynopsis: strings.TrimSpace(sysHelp["policy-list"][0]), HelpSynopsis: strings.TrimSpace(sysHelp["policy-list"][0]),
@ -1796,15 +2128,46 @@ func (b *SystemBackend) policyPaths() []*framework.Path {
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: &framework.PathOperation{ logical.ReadOperation: &framework.PathOperation{
Callback: b.handlePoliciesRead(PolicyTypeACL), Callback: b.handlePoliciesRead(PolicyTypeACL),
Summary: "Retrieve information about the named ACL policy.", Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"name": {
Type: framework.TypeString,
Required: false,
},
"rules": {
Type: framework.TypeString,
Required: false,
},
"policy": {
Type: framework.TypeString,
Required: false,
},
},
}},
},
Summary: "Retrieve information about the named ACL policy.",
}, },
logical.UpdateOperation: &framework.PathOperation{ logical.UpdateOperation: &framework.PathOperation{
Callback: b.handlePoliciesSet(PolicyTypeACL), Callback: b.handlePoliciesSet(PolicyTypeACL),
Summary: "Add a new or update an existing ACL policy.", Responses: map[int][]framework.Response{
http.StatusNoContent: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{},
}},
},
Summary: "Add a new or update an existing ACL policy.",
}, },
logical.DeleteOperation: &framework.PathOperation{ logical.DeleteOperation: &framework.PathOperation{
Callback: b.handlePoliciesDelete(PolicyTypeACL), Callback: b.handlePoliciesDelete(PolicyTypeACL),
Summary: "Delete the ACL policy with the given name.", Responses: map[int][]framework.Response{
http.StatusNoContent: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{},
}},
},
Summary: "Delete the ACL policy with the given name.",
}, },
}, },
@ -1818,7 +2181,18 @@ func (b *SystemBackend) policyPaths() []*framework.Path {
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ListOperation: &framework.PathOperation{ logical.ListOperation: &framework.PathOperation{
Callback: b.handlePoliciesPasswordList, Callback: b.handlePoliciesPasswordList,
Summary: "List the existing password policies.", Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"keys": {
Type: framework.TypeStringSlice,
Required: false,
},
},
}},
},
Summary: "List the existing password policies.",
}, },
}, },
}, },
@ -1836,7 +2210,18 @@ func (b *SystemBackend) policyPaths() []*framework.Path {
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: &framework.PathOperation{ logical.ReadOperation: &framework.PathOperation{
Callback: b.handlePoliciesPasswordGenerate, Callback: b.handlePoliciesPasswordGenerate,
Summary: "Generate a password from an existing password policy.", Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"password": {
Type: framework.TypeString,
Required: true,
},
},
}},
},
Summary: "Generate a password from an existing password policy.",
}, },
}, },
@ -1861,15 +2246,38 @@ func (b *SystemBackend) policyPaths() []*framework.Path {
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: &framework.PathOperation{ logical.UpdateOperation: &framework.PathOperation{
Callback: b.handlePoliciesPasswordSet, Callback: b.handlePoliciesPasswordSet,
Summary: "Add a new or update an existing password policy.", Responses: map[int][]framework.Response{
http.StatusNoContent: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{},
}},
},
Summary: "Add a new or update an existing password policy.",
}, },
logical.ReadOperation: &framework.PathOperation{ logical.ReadOperation: &framework.PathOperation{
Callback: b.handlePoliciesPasswordGet, Callback: b.handlePoliciesPasswordGet,
Summary: "Retrieve an existing password policy.", Responses: map[int][]framework.Response{
http.StatusNoContent: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"policy": {
Type: framework.TypeString,
Required: true,
},
},
}},
},
Summary: "Retrieve an existing password policy.",
}, },
logical.DeleteOperation: &framework.PathOperation{ logical.DeleteOperation: &framework.PathOperation{
Callback: b.handlePoliciesPasswordDelete, Callback: b.handlePoliciesPasswordDelete,
Summary: "Delete a password policy.", Responses: map[int][]framework.Response{
http.StatusNoContent: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{},
}},
},
Summary: "Delete a password policy.",
}, },
}, },
@ -2019,9 +2427,105 @@ func (b *SystemBackend) mountPaths() []*framework.Path {
}, },
}, },
Callbacks: map[logical.Operation]framework.OperationFunc{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: b.handleMountTuneRead, logical.ReadOperation: &framework.PathOperation{
logical.UpdateOperation: b.handleMountTuneWrite, Callback: b.handleMountTuneRead,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"max_lease_ttl": {
Type: framework.TypeInt,
Description: strings.TrimSpace(sysHelp["tune_max_lease_ttl"][0]),
Required: true,
},
"description": {
Type: framework.TypeString,
Description: strings.TrimSpace(sysHelp["auth_desc"][0]),
Required: true,
},
"default_lease_ttl": {
Type: framework.TypeInt,
Description: strings.TrimSpace(sysHelp["tune_default_lease_ttl"][0]),
Required: true,
},
"force_no_cache": {
Type: framework.TypeBool,
Required: true,
},
"token_type": {
Type: framework.TypeString,
Description: strings.TrimSpace(sysHelp["token_type"][0]),
Required: false,
},
"allowed_managed_keys": {
Type: framework.TypeCommaStringSlice,
Description: strings.TrimSpace(sysHelp["tune_allowed_managed_keys"][0]),
Required: false,
},
"allowed_response_headers": {
Type: framework.TypeCommaStringSlice,
Description: strings.TrimSpace(sysHelp["allowed_response_headers"][0]),
Required: false,
},
"options": {
Type: framework.TypeKVPairs,
Description: strings.TrimSpace(sysHelp["tune_mount_options"][0]),
Required: false,
},
"plugin_version": {
Type: framework.TypeString,
Description: strings.TrimSpace(sysHelp["plugin-catalog_version"][0]),
Required: false,
},
"external_entropy_access": {
Type: framework.TypeBool,
Required: false,
},
"audit_non_hmac_request_keys": {
Type: framework.TypeCommaStringSlice,
Required: false,
},
"audit_non_hmac_response_keys": {
Type: framework.TypeCommaStringSlice,
Required: false,
},
"listing_visibility": {
Type: framework.TypeString,
Required: false,
},
"passthrough_request_headers": {
Type: framework.TypeCommaStringSlice,
Required: false,
},
"user_lockout_counter_reset_duration": {
Type: framework.TypeInt64,
Required: false,
},
"user_lockout_threshold": {
Type: framework.TypeInt64, // TODO this is actuall a Uint64 do we need a new type?
Required: false,
},
"user_lockout_duration": {
Type: framework.TypeInt64,
Required: false,
},
"user_lockout_disable": {
Type: framework.TypeBool,
Required: false,
},
},
}},
},
},
logical.UpdateOperation: &framework.PathOperation{
Callback: b.handleMountTuneWrite,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
}},
},
},
}, },
HelpSynopsis: strings.TrimSpace(sysHelp["mount_tune"][0]), HelpSynopsis: strings.TrimSpace(sysHelp["mount_tune"][0]),
@ -2080,15 +2584,93 @@ func (b *SystemBackend) mountPaths() []*framework.Path {
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: &framework.PathOperation{ logical.ReadOperation: &framework.PathOperation{
Callback: b.handleReadMount, Callback: b.handleReadMount,
Summary: "Read the configuration of the secret engine at the given path.", Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{
"type": {
Type: framework.TypeString,
Description: strings.TrimSpace(sysHelp["mount_type"][0]),
Required: true,
},
"description": {
Type: framework.TypeString,
Description: strings.TrimSpace(sysHelp["mount_desc"][0]),
Required: true,
},
"accessor": {
Type: framework.TypeString,
Required: true,
},
"local": {
Type: framework.TypeBool,
Default: false,
Description: strings.TrimSpace(sysHelp["mount_local"][0]),
Required: true,
},
"seal_wrap": {
Type: framework.TypeBool,
Default: false,
Description: strings.TrimSpace(sysHelp["seal_wrap"][0]),
Required: true,
},
"external_entropy_access": {
Type: framework.TypeBool,
Required: true,
},
"options": {
Type: framework.TypeKVPairs,
Description: strings.TrimSpace(sysHelp["mount_options"][0]),
Required: true,
},
"plugin_version": {
Type: framework.TypeString,
Description: strings.TrimSpace(sysHelp["plugin-catalog_version"][0]),
Required: true,
},
"uuid": {
Type: framework.TypeString,
Required: true,
},
"running_plugin_version": {
Type: framework.TypeString,
Required: true,
},
"running_sha256": {
Type: framework.TypeString,
Required: true,
},
"config": {
Type: framework.TypeMap,
Description: strings.TrimSpace(sysHelp["mount_config"][0]),
Required: true,
},
"deprecation_status": {
Type: framework.TypeString,
Required: false,
},
},
}},
},
Summary: "Read the configuration of the secret engine at the given path.",
}, },
logical.UpdateOperation: &framework.PathOperation{ logical.UpdateOperation: &framework.PathOperation{
Callback: b.handleMount, Callback: b.handleMount,
Summary: "Enable a new secrets engine at the given path.", Responses: map[int][]framework.Response{
http.StatusNoContent: {{
Description: "OK",
}},
},
Summary: "Enable a new secrets engine at the given path.",
}, },
logical.DeleteOperation: &framework.PathOperation{ logical.DeleteOperation: &framework.PathOperation{
Callback: b.handleUnmount, Callback: b.handleUnmount,
Summary: "Disable the mount point specified at the given path.", Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
}},
},
Summary: "Disable the mount point specified at the given path.",
}, },
}, },
HelpSynopsis: strings.TrimSpace(sysHelp["mount"][0]), HelpSynopsis: strings.TrimSpace(sysHelp["mount"][0]),
@ -2098,8 +2680,16 @@ func (b *SystemBackend) mountPaths() []*framework.Path {
{ {
Pattern: "mounts$", Pattern: "mounts$",
Callbacks: map[logical.Operation]framework.OperationFunc{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: b.handleMountTable, logical.ReadOperation: &framework.PathOperation{
Callback: b.handleMountTable,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
Fields: map[string]*framework.FieldSchema{},
}},
},
},
}, },
HelpSynopsis: strings.TrimSpace(sysHelp["mounts"][0]), HelpSynopsis: strings.TrimSpace(sysHelp["mounts"][0]),

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"net/http"
"net/http/pprof" "net/http/pprof"
"strconv" "strconv"
@ -19,7 +20,12 @@ func (b *SystemBackend) pprofPaths() []*framework.Path {
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: &framework.PathOperation{ logical.ReadOperation: &framework.PathOperation{
Callback: b.handlePprofIndex, Callback: b.handlePprofIndex,
Summary: "Returns an HTML page listing the available profiles.", Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
}},
},
Summary: "Returns an HTML page listing the available profiles.",
Description: `Returns an HTML page listing the available Description: `Returns an HTML page listing the available
profiles. This should be mainly accessed via browsers or applications that can profiles. This should be mainly accessed via browsers or applications that can
render pages.`, render pages.`,
@ -31,7 +37,12 @@ render pages.`,
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: &framework.PathOperation{ logical.ReadOperation: &framework.PathOperation{
Callback: b.handlePprofCmdline, Callback: b.handlePprofCmdline,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
}},
},
Summary: "Returns the running program's command line.", Summary: "Returns the running program's command line.",
Description: "Returns the running program's command line, with arguments separated by NUL bytes.", Description: "Returns the running program's command line, with arguments separated by NUL bytes.",
}, },
@ -42,7 +53,12 @@ render pages.`,
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: &framework.PathOperation{ logical.ReadOperation: &framework.PathOperation{
Callback: b.handlePprofGoroutine, Callback: b.handlePprofGoroutine,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
}},
},
Summary: "Returns stack traces of all current goroutines.", Summary: "Returns stack traces of all current goroutines.",
Description: "Returns stack traces of all current goroutines.", Description: "Returns stack traces of all current goroutines.",
}, },
@ -53,7 +69,12 @@ render pages.`,
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: &framework.PathOperation{ logical.ReadOperation: &framework.PathOperation{
Callback: b.handlePprofHeap, Callback: b.handlePprofHeap,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
}},
},
Summary: "Returns a sampling of memory allocations of live object.", Summary: "Returns a sampling of memory allocations of live object.",
Description: "Returns a sampling of memory allocations of live object.", Description: "Returns a sampling of memory allocations of live object.",
}, },
@ -64,7 +85,12 @@ render pages.`,
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: &framework.PathOperation{ logical.ReadOperation: &framework.PathOperation{
Callback: b.handlePprofAllocs, Callback: b.handlePprofAllocs,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
}},
},
Summary: "Returns a sampling of all past memory allocations.", Summary: "Returns a sampling of all past memory allocations.",
Description: "Returns a sampling of all past memory allocations.", Description: "Returns a sampling of all past memory allocations.",
}, },
@ -75,7 +101,13 @@ render pages.`,
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: &framework.PathOperation{ logical.ReadOperation: &framework.PathOperation{
Callback: b.handlePprofThreadcreate, Callback: b.handlePprofThreadcreate,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
}},
},
Summary: "Returns stack traces that led to the creation of new OS threads", Summary: "Returns stack traces that led to the creation of new OS threads",
Description: "Returns stack traces that led to the creation of new OS threads", Description: "Returns stack traces that led to the creation of new OS threads",
}, },
@ -86,7 +118,12 @@ render pages.`,
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: &framework.PathOperation{ logical.ReadOperation: &framework.PathOperation{
Callback: b.handlePprofBlock, Callback: b.handlePprofBlock,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
}},
},
Summary: "Returns stack traces that led to blocking on synchronization primitives", Summary: "Returns stack traces that led to blocking on synchronization primitives",
Description: "Returns stack traces that led to blocking on synchronization primitives", Description: "Returns stack traces that led to blocking on synchronization primitives",
}, },
@ -97,7 +134,12 @@ render pages.`,
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: &framework.PathOperation{ logical.ReadOperation: &framework.PathOperation{
Callback: b.handlePprofMutex, Callback: b.handlePprofMutex,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
}},
},
Summary: "Returns stack traces of holders of contended mutexes", Summary: "Returns stack traces of holders of contended mutexes",
Description: "Returns stack traces of holders of contended mutexes", Description: "Returns stack traces of holders of contended mutexes",
}, },
@ -115,7 +157,12 @@ render pages.`,
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: &framework.PathOperation{ logical.ReadOperation: &framework.PathOperation{
Callback: b.handlePprofProfile, Callback: b.handlePprofProfile,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
}},
},
Summary: "Returns a pprof-formatted cpu profile payload.", Summary: "Returns a pprof-formatted cpu profile payload.",
Description: "Returns a pprof-formatted cpu profile payload. Profiling lasts for duration specified in seconds GET parameter, or for 30 seconds if not specified.", Description: "Returns a pprof-formatted cpu profile payload. Profiling lasts for duration specified in seconds GET parameter, or for 30 seconds if not specified.",
}, },
@ -126,7 +173,12 @@ render pages.`,
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: &framework.PathOperation{ logical.ReadOperation: &framework.PathOperation{
Callback: b.handlePprofSymbol, Callback: b.handlePprofSymbol,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
}},
},
Summary: "Returns the program counters listed in the request.", Summary: "Returns the program counters listed in the request.",
Description: "Returns the program counters listed in the request.", Description: "Returns the program counters listed in the request.",
}, },
@ -145,7 +197,12 @@ render pages.`,
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.ReadOperation: &framework.PathOperation{ logical.ReadOperation: &framework.PathOperation{
Callback: b.handlePprofTrace, Callback: b.handlePprofTrace,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
}},
},
Summary: "Returns the execution trace in binary form.", Summary: "Returns the execution trace in binary form.",
Description: "Returns the execution trace in binary form. Tracing lasts for duration specified in seconds GET parameter, or for 1 second if not specified.", Description: "Returns the execution trace in binary form. Tracing lasts for duration specified in seconds GET parameter, or for 1 second if not specified.",
}, },

View File

@ -248,6 +248,14 @@ func TestSystemBackend_mounts(t *testing.T) {
if diff := deep.Equal(resp.Data, conf); len(diff) > 0 { if diff := deep.Equal(resp.Data, conf); len(diff) > 0 {
t.Fatalf("bad, diff: %#v", diff) t.Fatalf("bad, diff: %#v", diff)
} }
// validate the response structure for mount named read
schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
} }
} }
@ -270,9 +278,14 @@ func TestSystemBackend_mount(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
if resp != nil {
t.Fatalf("bad: %v", resp) // validate the response structure for mount named update
} schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
req = logical.TestRequest(t, logical.ReadOperation, "mounts") req = logical.TestRequest(t, logical.ReadOperation, "mounts")
resp, err = b.HandleRequest(namespace.RootContext(nil), req) resp, err = b.HandleRequest(namespace.RootContext(nil), req)
@ -433,9 +446,14 @@ func TestSystemBackend_unmount(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
if resp != nil {
t.Fatalf("bad: %v", resp) // validate the response structure for mount named delete
} schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
} }
var capabilitiesPolicy = ` var capabilitiesPolicy = `
@ -1095,6 +1113,15 @@ func TestSystemBackend_leases(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
// validate the response structure for Update
schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
if resp.Data["renewable"] == nil || resp.Data["renewable"].(bool) { if resp.Data["renewable"] == nil || resp.Data["renewable"].(bool) {
t.Fatal("kv leases are not renewable") t.Fatal("kv leases are not renewable")
} }
@ -1144,9 +1171,14 @@ func TestSystemBackend_leases_list(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
if resp == nil || resp.Data == nil {
t.Fatalf("bad: %#v", resp) // validate the response body for list
} schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
var keys []string var keys []string
if err := mapstructure.WeakDecode(resp.Data["keys"], &keys); err != nil { if err := mapstructure.WeakDecode(resp.Data["keys"], &keys); err != nil {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
@ -1305,6 +1337,14 @@ func TestSystemBackend_renew(t *testing.T) {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
// Validate lease renewal response structure
schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req2.Path), req2.Operation),
resp,
true,
)
// Should get error about non-renewability // Should get error about non-renewability
if resp2.Data["error"] != "lease is not renewable" { if resp2.Data["error"] != "lease is not renewable" {
t.Fatalf("bad: %#v", resp) t.Fatalf("bad: %#v", resp)
@ -1563,6 +1603,15 @@ func TestSystemBackend_revoke_invalidID(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
// validate the response structure for lease revoke
schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
if resp != nil { if resp != nil {
t.Fatalf("bad: %v", resp) t.Fatalf("bad: %v", resp)
} }
@ -1630,9 +1679,14 @@ func TestSystemBackend_revokePrefix(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("err: %v %#v", err, resp2) t.Fatalf("err: %v %#v", err, resp2)
} }
if resp2 != nil {
t.Fatalf("bad: %#v", resp) // validate the response structure for lease revoke-prefix
} schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req2.Path), req2.Operation),
resp,
true,
)
// Attempt renew // Attempt renew
req3 := logical.TestRequest(t, logical.UpdateOperation, "leases/renew/"+resp.Secret.LeaseID) req3 := logical.TestRequest(t, logical.UpdateOperation, "leases/renew/"+resp.Secret.LeaseID)
@ -2066,6 +2120,14 @@ func TestSystemBackend_policyList(t *testing.T) {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
// validate the response structure for policy read
schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
exp := map[string]interface{}{ exp := map[string]interface{}{
"keys": []string{"default", "root"}, "keys": []string{"default", "root"},
"policies": []string{"default", "root"}, "policies": []string{"default", "root"},
@ -2090,6 +2152,14 @@ func TestSystemBackend_policyCRUD(t *testing.T) {
t.Fatalf("bad: %#v", resp) t.Fatalf("bad: %#v", resp)
} }
// validate the response structure for policy named Update
schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
// Read the policy // Read the policy
req = logical.TestRequest(t, logical.ReadOperation, "policy/foo") req = logical.TestRequest(t, logical.ReadOperation, "policy/foo")
resp, err = b.HandleRequest(namespace.RootContext(nil), req) resp, err = b.HandleRequest(namespace.RootContext(nil), req)
@ -2097,6 +2167,14 @@ func TestSystemBackend_policyCRUD(t *testing.T) {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
// validate the response structure for policy named read
schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
exp := map[string]interface{}{ exp := map[string]interface{}{
"name": "foo", "name": "foo",
"rules": rules, "rules": rules,
@ -2145,6 +2223,14 @@ func TestSystemBackend_policyCRUD(t *testing.T) {
t.Fatalf("bad: %#v", resp) t.Fatalf("bad: %#v", resp)
} }
// validate the response structure for policy named delete
schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
// Read the policy (deleted) // Read the policy (deleted)
req = logical.TestRequest(t, logical.ReadOperation, "policy/foo") req = logical.TestRequest(t, logical.ReadOperation, "policy/foo")
resp, err = b.HandleRequest(namespace.RootContext(nil), req) resp, err = b.HandleRequest(namespace.RootContext(nil), req)
@ -2189,7 +2275,6 @@ func TestSystemBackend_enableAudit(t *testing.T) {
func TestSystemBackend_auditHash(t *testing.T) { func TestSystemBackend_auditHash(t *testing.T) {
c, b, _ := testCoreSystemBackend(t) c, b, _ := testCoreSystemBackend(t)
paths := b.(*SystemBackend).auditPaths()
c.auditBackends["noop"] = corehelpers.NoopAuditFactory(nil) c.auditBackends["noop"] = corehelpers.NoopAuditFactory(nil)
req := logical.TestRequest(t, logical.UpdateOperation, "audit/foo") req := logical.TestRequest(t, logical.UpdateOperation, "audit/foo")
@ -2202,9 +2287,10 @@ func TestSystemBackend_auditHash(t *testing.T) {
if resp != nil { if resp != nil {
t.Fatalf("bad: %v", resp) t.Fatalf("bad: %v", resp)
} }
schema.ValidateResponse( schema.ValidateResponse(
t, t,
schema.FindResponseSchema(t, paths, 2, req.Operation), schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp, resp,
true, true,
) )
@ -2219,9 +2305,10 @@ func TestSystemBackend_auditHash(t *testing.T) {
if resp == nil || resp.Data == nil { if resp == nil || resp.Data == nil {
t.Fatalf("response or its data was nil") t.Fatalf("response or its data was nil")
} }
schema.ValidateResponse( schema.ValidateResponse(
t, t,
schema.FindResponseSchema(t, paths, 0, req.Operation), schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp, resp,
true, true,
) )
@ -2985,6 +3072,13 @@ func TestSystemBackend_PluginCatalog_CRUD(t *testing.T) {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
if len(resp.Data["keys"].([]string)) != len(c.builtinRegistry.Keys(consts.PluginTypeDatabase)) { if len(resp.Data["keys"].([]string)) != len(c.builtinRegistry.Keys(consts.PluginTypeDatabase)) {
t.Fatalf("Wrong number of plugins, got %d, expected %d", len(resp.Data["keys"].([]string)), len(builtinplugins.Registry.Keys(consts.PluginTypeDatabase))) t.Fatalf("Wrong number of plugins, got %d, expected %d", len(resp.Data["keys"].([]string)), len(builtinplugins.Registry.Keys(consts.PluginTypeDatabase)))
} }
@ -2995,6 +3089,13 @@ func TestSystemBackend_PluginCatalog_CRUD(t *testing.T) {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
// Get deprecation status directly from the registry so we can compare it to the API response // Get deprecation status directly from the registry so we can compare it to the API response
deprecationStatus, _ := c.builtinRegistry.DeprecationStatus("mysql-database-plugin", consts.PluginTypeDatabase) deprecationStatus, _ := c.builtinRegistry.DeprecationStatus("mysql-database-plugin", consts.PluginTypeDatabase)
@ -3033,6 +3134,13 @@ func TestSystemBackend_PluginCatalog_CRUD(t *testing.T) {
t.Fatalf("err: %v", resp.Error()) t.Fatalf("err: %v", resp.Error())
} }
schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
delete(req.Data, "args") delete(req.Data, "args")
resp, err = b.HandleRequest(namespace.RootContext(nil), req) resp, err = b.HandleRequest(namespace.RootContext(nil), req)
if err != nil || resp.Error() != nil { if err != nil || resp.Error() != nil {
@ -3065,6 +3173,13 @@ func TestSystemBackend_PluginCatalog_CRUD(t *testing.T) {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
} }
schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
req = logical.TestRequest(t, logical.ReadOperation, "plugins/catalog/database/test-plugin") req = logical.TestRequest(t, logical.ReadOperation, "plugins/catalog/database/test-plugin")
resp, err = b.HandleRequest(namespace.RootContext(nil), req) resp, err = b.HandleRequest(namespace.RootContext(nil), req)
if resp != nil || err != nil { if resp != nil || err != nil {
@ -3490,6 +3605,14 @@ func TestSystemBackend_InternalUIMounts(t *testing.T) {
t.Fatalf("resp.Error: %v, err:%v", resp.Error(), err) t.Fatalf("resp.Error: %v, err:%v", resp.Error(), err)
} }
// validate the response structure for mount update
schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
req = logical.TestRequest(t, logical.ReadOperation, "internal/ui/mounts") req = logical.TestRequest(t, logical.ReadOperation, "internal/ui/mounts")
resp, err = b.HandleRequest(namespace.RootContext(nil), req) resp, err = b.HandleRequest(namespace.RootContext(nil), req)
if err != nil { if err != nil {
@ -4828,7 +4951,6 @@ func TestSystemBackend_Loggers(t *testing.T) {
t.Parallel() t.Parallel()
core, b, _ := testCoreSystemBackend(t) core, b, _ := testCoreSystemBackend(t)
// Test core overrides logging level outside of config, // Test core overrides logging level outside of config,
// an initial delete will ensure that we an initial read // an initial delete will ensure that we an initial read
// to get expected values is based off of config and not // to get expected values is based off of config and not
@ -4843,6 +4965,13 @@ func TestSystemBackend_Loggers(t *testing.T) {
t.Fatalf("unexpected error, err: %v, resp: %#v", err, resp) t.Fatalf("unexpected error, err: %v, resp: %#v", err, resp)
} }
schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
req = &logical.Request{ req = &logical.Request{
Path: "loggers", Path: "loggers",
Operation: logical.ReadOperation, Operation: logical.ReadOperation,
@ -4853,6 +4982,13 @@ func TestSystemBackend_Loggers(t *testing.T) {
t.Fatalf("unexpected error, err: %v, resp: %#v", err, resp) t.Fatalf("unexpected error, err: %v, resp: %#v", err, resp)
} }
schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
initialLoggers := resp.Data initialLoggers := resp.Data
req = &logical.Request{ req = &logical.Request{
@ -4866,6 +5002,13 @@ func TestSystemBackend_Loggers(t *testing.T) {
resp, err = b.HandleRequest(namespace.RootContext(nil), req) resp, err = b.HandleRequest(namespace.RootContext(nil), req)
respIsError := resp != nil && resp.IsError() respIsError := resp != nil && resp.IsError()
schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
if err != nil || (!tc.expectError && respIsError) { if err != nil || (!tc.expectError && respIsError) {
t.Fatalf("unexpected error, err: %v, resp: %#v", err, resp) t.Fatalf("unexpected error, err: %v, resp: %#v", err, resp)
} }
@ -4885,6 +5028,13 @@ func TestSystemBackend_Loggers(t *testing.T) {
t.Fatalf("unexpected error, err: %v, resp: %#v", err, resp) t.Fatalf("unexpected error, err: %v, resp: %#v", err, resp)
} }
schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
for _, logger := range core.allLoggers { for _, logger := range core.allLoggers {
loggerName := logger.Name() loggerName := logger.Name()
levelRaw, ok := resp.Data[loggerName] levelRaw, ok := resp.Data[loggerName]
@ -4909,6 +5059,13 @@ func TestSystemBackend_Loggers(t *testing.T) {
t.Fatalf("unexpected error, err: %v, resp: %#v", err, resp) t.Fatalf("unexpected error, err: %v, resp: %#v", err, resp)
} }
schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
req = &logical.Request{ req = &logical.Request{
Path: "loggers", Path: "loggers",
Operation: logical.ReadOperation, Operation: logical.ReadOperation,
@ -4919,6 +5076,13 @@ func TestSystemBackend_Loggers(t *testing.T) {
t.Fatalf("unexpected error, err: %v, resp: %#v", err, resp) t.Fatalf("unexpected error, err: %v, resp: %#v", err, resp)
} }
schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
for _, logger := range core.allLoggers { for _, logger := range core.allLoggers {
loggerName := logger.Name() loggerName := logger.Name()
levelRaw, currentOk := resp.Data[loggerName] levelRaw, currentOk := resp.Data[loggerName]

View File

@ -83,7 +83,12 @@ func (b *SystemBackend) loginMFAPaths() []*framework.Path {
}, },
Operations: map[logical.Operation]framework.OperationHandler{ Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: &framework.PathOperation{ logical.UpdateOperation: &framework.PathOperation{
Callback: b.Core.loginMFABackend.handleMFALoginValidate, Callback: b.Core.loginMFABackend.handleMFALoginValidate,
Responses: map[int][]framework.Response{
http.StatusOK: {{
Description: "OK",
}},
},
Summary: "Validates the login for the given MFA methods. Upon successful validation, it returns an auth response containing the client token", Summary: "Validates the login for the given MFA methods. Upon successful validation, it returns an auth response containing the client token",
ForwardPerformanceStandby: true, ForwardPerformanceStandby: true,
}, },