Skip to content

Commit

Permalink
Revert "Add mount path into the default generated openapi.json spec (#…
Browse files Browse the repository at this point in the history
…17926)" (#18617)

* Revert "Add mount path into the default generated openapi.json spec (UI) (#17926)"

This reverts commit db8efac.

* Revert "Remove `generic_mount_paths` field (#18558)"

This reverts commit 79c8f62.
  • Loading branch information
averche authored and AnPucel committed Feb 3, 2023
1 parent b626f28 commit 1c1b8a5
Show file tree
Hide file tree
Showing 13 changed files with 119 additions and 108 deletions.
6 changes: 3 additions & 3 deletions api/plugin_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ const (
// path matches that path or not (useful specifically for the paths that
// contain templated fields.)
var sudoPaths = map[string]*regexp.Regexp{
"/auth/{token_mount_path}/accessors/": regexp.MustCompile(`^/auth/.+/accessors/$`),
"/{pki_mount_path}/root": regexp.MustCompile(`^/.+/root$`),
"/{pki_mount_path}/root/sign-self-issued": regexp.MustCompile(`^/.+/root/sign-self-issued$`),
"/auth/token/accessors/": regexp.MustCompile(`^/auth/token/accessors/$`),
"/pki/root": regexp.MustCompile(`^/pki/root$`),
"/pki/root/sign-self-issued": regexp.MustCompile(`^/pki/root/sign-self-issued$`),
"/sys/audit": regexp.MustCompile(`^/sys/audit$`),
"/sys/audit/{path}": regexp.MustCompile(`^/sys/audit/.+$`),
"/sys/auth/{path}": regexp.MustCompile(`^/sys/auth/.+$`),
Expand Down
9 changes: 8 additions & 1 deletion sdk/framework/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,13 @@ func (b *Backend) handleRootHelp(req *logical.Request) (*logical.Response, error
// names in the OAS document.
requestResponsePrefix := req.GetString("requestResponsePrefix")

// Generic mount paths will primarily be used for code generation purposes.
// This will result in dynamic mount paths being placed instead of
// hardcoded default paths. For example /auth/approle/login would be replaced
// with /auth/{mountPath}/login. This will be replaced for all secrets
// engines and auth methods that are enabled.
genericMountPaths, _ := req.Get("genericMountPaths").(bool)

// Build OpenAPI response for the entire backend
vaultVersion := "unknown"
if b.System() != nil {
Expand All @@ -550,7 +557,7 @@ func (b *Backend) handleRootHelp(req *logical.Request) (*logical.Response, error
}

doc := NewOASDocument(vaultVersion)
if err := documentPaths(b, requestResponsePrefix, doc); err != nil {
if err := documentPaths(b, requestResponsePrefix, genericMountPaths, doc); err != nil {
b.Logger().Warn("error generating OpenAPI", "error", err)
}

Expand Down
33 changes: 11 additions & 22 deletions sdk/framework/openapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,16 +208,16 @@ var (
altRootsRe = regexp.MustCompile(`^\(([\w\-_]+(?:\|[\w\-_]+)+)\)(/.*)$`) // Pattern starting with alts, e.g. "(root1|root2)/(?P<name>regex)"
cleanCharsRe = regexp.MustCompile("[()^$?]") // Set of regex characters that will be stripped during cleaning
cleanSuffixRe = regexp.MustCompile(`/\?\$?$`) // Path suffix patterns that will be stripped during cleaning
nonWordRe = regexp.MustCompile(`[^a-zA-Z0-9]+`) // Match a sequence of non-word characters
nonWordRe = regexp.MustCompile(`[^\w]+`) // Match a sequence of non-word characters
pathFieldsRe = regexp.MustCompile(`{(\w+)}`) // Capture OpenAPI-style named parameters, e.g. "lookup/{urltoken}",
reqdRe = regexp.MustCompile(`\(?\?P<(\w+)>[^)]*\)?`) // Capture required parameters, e.g. "(?P<name>regex)"
wsRe = regexp.MustCompile(`\s+`) // Match whitespace, to be compressed during cleaning
)

// documentPaths parses all paths in a framework.Backend into OpenAPI paths.
func documentPaths(backend *Backend, requestResponsePrefix string, doc *OASDocument) error {
func documentPaths(backend *Backend, requestResponsePrefix string, genericMountPaths bool, doc *OASDocument) error {
for _, p := range backend.Paths {
if err := documentPath(p, backend.SpecialPaths(), requestResponsePrefix, backend.BackendType, doc); err != nil {
if err := documentPath(p, backend.SpecialPaths(), requestResponsePrefix, genericMountPaths, backend.BackendType, doc); err != nil {
return err
}
}
Expand All @@ -226,7 +226,7 @@ func documentPaths(backend *Backend, requestResponsePrefix string, doc *OASDocum
}

// documentPath parses a framework.Path into one or more OpenAPI paths.
func documentPath(p *Path, specialPaths *logical.Paths, requestResponsePrefix string, backendType logical.BackendType, doc *OASDocument) error {
func documentPath(p *Path, specialPaths *logical.Paths, requestResponsePrefix string, genericMountPaths bool, backendType logical.BackendType, doc *OASDocument) error {
var sudoPaths []string
var unauthPaths []string

Expand Down Expand Up @@ -265,21 +265,16 @@ func documentPath(p *Path, specialPaths *logical.Paths, requestResponsePrefix st
// Body fields will be added to individual operations.
pathFields, bodyFields := splitFields(p.Fields, path)

defaultMountPath := requestResponsePrefix
if requestResponsePrefix == "kv" {
defaultMountPath = "secret"
}

if defaultMountPath != "system" && defaultMountPath != "identity" {
if genericMountPaths && requestResponsePrefix != "system" && requestResponsePrefix != "identity" {
// Add mount path as a parameter
p := OASParameter{
Name: fmt.Sprintf("%s_mount_path", defaultMountPath),
Description: "Path where the backend was mounted; the endpoint path will be offset by the mount path",
Name: "mountPath",
Description: "Path that the backend was mounted at",
In: "path",
Schema: &OASSchema{
Type: "string",
Default: defaultMountPath,
Type: "string",
},
Required: false,
Required: true,
}

pi.Parameters = append(pi.Parameters, p)
Expand Down Expand Up @@ -785,9 +780,6 @@ func cleanResponse(resp *logical.Response) *cleanedResponse {
//
// An optional user-provided suffix ("context") may also be appended.
func (d *OASDocument) CreateOperationIDs(context string) {
// title caser
title := cases.Title(language.English)

opIDCount := make(map[string]int)
var paths []string

Expand All @@ -814,12 +806,9 @@ func (d *OASDocument) CreateOperationIDs(context string) {
continue
}

// Discard "_mount_path" from any {thing_mount_path} parameters
path = strings.Replace(path, "_mount_path", "", 1)

// Space-split on non-words, title case everything, recombine
opID := nonWordRe.ReplaceAllString(strings.ToLower(path), " ")
opID = title.String(opID)
opID = strings.Title(opID)
opID = method + strings.ReplaceAll(opID, " ", "")

// deduplicate operationIds. This is a safeguard, since generated IDs should
Expand Down
12 changes: 5 additions & 7 deletions sdk/framework/openapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ func TestOpenAPI_SpecialPaths(t *testing.T) {
Root: test.rootPaths,
Unauthenticated: test.unauthPaths,
}
err := documentPath(&path, sp, "kv", logical.TypeLogical, doc)
err := documentPath(&path, sp, "kv", false, logical.TypeLogical, doc)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -528,11 +528,11 @@ func TestOpenAPI_OperationID(t *testing.T) {

for _, context := range []string{"", "bar"} {
doc := NewOASDocument("version")
err := documentPath(path1, nil, "kv", logical.TypeLogical, doc)
err := documentPath(path1, nil, "kv", false, logical.TypeLogical, doc)
if err != nil {
t.Fatal(err)
}
err = documentPath(path2, nil, "kv", logical.TypeLogical, doc)
err = documentPath(path2, nil, "kv", false, logical.TypeLogical, doc)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -592,7 +592,7 @@ func TestOpenAPI_CustomDecoder(t *testing.T) {
}

docOrig := NewOASDocument("version")
err := documentPath(p, nil, "kv", logical.TypeLogical, docOrig)
err := documentPath(p, nil, "kv", false, logical.TypeLogical, docOrig)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -655,7 +655,7 @@ func testPath(t *testing.T, path *Path, sp *logical.Paths, expectedJSON string)
t.Helper()

doc := NewOASDocument("dummyversion")
if err := documentPath(path, sp, "kv", logical.TypeLogical, doc); err != nil {
if err := documentPath(path, sp, "kv", false, logical.TypeLogical, doc); err != nil {
t.Fatal(err)
}
doc.CreateOperationIDs("")
Expand All @@ -665,8 +665,6 @@ func testPath(t *testing.T, path *Path, sp *logical.Paths, expectedJSON string)
t.Fatal(err)
}

t.Log(string(docJSON))

// Compare json by first decoding, then comparing with a deep equality check.
var expected, actual interface{}
if err := jsonutil.DecodeJSON(docJSON, &actual); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion sdk/framework/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ func (p *Path) helpCallback(b *Backend) OperationFunc {
}
}
doc := NewOASDocument(vaultVersion)
if err := documentPath(p, b.SpecialPaths(), requestResponsePrefix, b.BackendType, doc); err != nil {
if err := documentPath(p, b.SpecialPaths(), requestResponsePrefix, false, b.BackendType, doc); err != nil {
b.Logger().Warn("error generating OpenAPI", "error", err)
}

Expand Down
9 changes: 0 additions & 9 deletions sdk/framework/testdata/legacy.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,6 @@
"type": "string"
},
"required": true
},
{
"name": "secret_mount_path",
"description": "Path where the backend was mounted; the endpoint path will be offset by the mount path",
"in": "path",
"schema": {
"type": "string",
"default": "secret"
}
}
],
"get": {
Expand Down
9 changes: 0 additions & 9 deletions sdk/framework/testdata/operations.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,6 @@
"type": "string"
},
"required": true
},
{
"name": "secret_mount_path",
"description": "Path where the backend was mounted; the endpoint path will be offset by the mount path",
"in": "path",
"schema": {
"type": "string",
"default": "secret"
}
}
],
"get": {
Expand Down
9 changes: 0 additions & 9 deletions sdk/framework/testdata/operations_list.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,6 @@
"type": "string"
},
"required": true
},
{
"name": "secret_mount_path",
"description": "Path where the backend was mounted; the endpoint path will be offset by the mount path",
"in": "path",
"schema": {
"type": "string",
"default": "secret"
}
}
],
"get": {
Expand Down
11 changes: 0 additions & 11 deletions sdk/framework/testdata/responses.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,6 @@
"paths": {
"/foo": {
"description": "Synopsis",
"parameters": [
{
"name": "secret_mount_path",
"description": "Path where the backend was mounted; the endpoint path will be offset by the mount path",
"in": "path",
"schema": {
"type": "string",
"default": "secret"
}
}
],
"x-vault-unauthenticated": true,
"delete": {
"operationId": "deleteFoo",
Expand Down
40 changes: 18 additions & 22 deletions ui/app/services/path-help.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Model from '@ember-data/model';
import Service from '@ember/service';
import { encodePath } from 'vault/utils/path-encoding-helpers';
import { getOwner } from '@ember/application';
import { assign } from '@ember/polyfills';
import { expandOpenApiProps, combineAttributes } from 'vault/utils/openapi-to-attrs';
import fieldToAttrs from 'vault/utils/field-to-attrs';
import { resolve, reject } from 'rsvp';
Expand Down Expand Up @@ -178,36 +179,31 @@ export default Service.extend({
// Returns relevant information from OpenAPI
// as determined by the expandOpenApiProps util
getProps(helpUrl, backend) {
// add name of thing you want
debug(`Fetching schema properties for ${backend} from ${helpUrl}`);

return this.ajax(helpUrl, backend).then((help) => {
// help.openapi.paths is an array with one item
const path = Object.keys(help.openapi.paths)[0];
// paths is an array but it will have a single entry
// for the scope we're in
const path = Object.keys(help.openapi.paths)[0]; // do this or look at name
const pathInfo = help.openapi.paths[path];
const params = pathInfo.parameters;
const paramProp = {};

// include url params
if (params) {
params.forEach((param) => {
const { name, schema, description } = param;
if (name === '_mount_path') {
// this param refers to the engine mount path,
// which is already accounted for as backend
return;
}
const label = capitalize(name.split('_').join(' '));

paramProp[name] = {
'x-vault-displayAttrs': {
name: label,
group: 'default',
},
type: schema.type,
description: description,
isId: true,
};
});
const { name, schema, description } = params[0];
const label = capitalize(name.split('_').join(' '));

paramProp[name] = {
'x-vault-displayAttrs': {
name: label,
group: 'default',
},
type: schema.type,
description: description,
isId: true,
};
}

let props = {};
Expand All @@ -224,7 +220,7 @@ export default Service.extend({
}
// put url params (e.g. {name}, {role})
// at the front of the props list
const newProps = { ...paramProp, ...props };
const newProps = assign({}, paramProp, props);
return expandOpenApiProps(newProps);
});
},
Expand Down
20 changes: 10 additions & 10 deletions vault/logical_system.go
Original file line number Diff line number Diff line change
Expand Up @@ -4503,6 +4503,8 @@ func (b *SystemBackend) pathInternalOpenAPI(ctx context.Context, req *logical.Re
// be received from plugin backends.
doc := framework.NewOASDocument(version.Version)

genericMountPaths, _ := d.Get("generic_mount_paths").(bool)

procMountGroup := func(group, mountPrefix string) error {
for mount, entry := range resp.Data[group].(map[string]interface{}) {

Expand All @@ -4520,7 +4522,7 @@ func (b *SystemBackend) pathInternalOpenAPI(ctx context.Context, req *logical.Re
req := &logical.Request{
Operation: logical.HelpOperation,
Storage: req.Storage,
Data: map[string]interface{}{"requestResponsePrefix": pluginType},
Data: map[string]interface{}{"requestResponsePrefix": pluginType, "genericMountPaths": genericMountPaths},
}

resp, err := backend.HandleRequest(ctx, req)
Expand Down Expand Up @@ -4574,16 +4576,12 @@ func (b *SystemBackend) pathInternalOpenAPI(ctx context.Context, req *logical.Re
}
}

var docPath string
if mount == "kv/" {
docPath = fmt.Sprintf("/%s{secret_mount_path}/%s", mountPrefix, path)
} else if mount != "sys/" && mount != "identity/" {
docPath = fmt.Sprintf("/%s{%s_mount_path}/%s", mountPrefix, strings.TrimRight(mount, "/"), path)
if genericMountPaths && mount != "sys/" && mount != "identity/" {
s := fmt.Sprintf("/%s{mountPath}/%s", mountPrefix, path)
doc.Paths[s] = obj
} else {
docPath = fmt.Sprintf("/%s%s%s", mountPrefix, mount, path)
doc.Paths["/"+mountPrefix+mount+path] = obj
}

doc.Paths[docPath] = obj
}

// Merge backend schema components
Expand Down Expand Up @@ -5093,7 +5091,9 @@ func sanitizePath(path string) string {
path += "/"
}

path = strings.TrimPrefix(path, "/")
if strings.HasPrefix(path, "/") {
path = path[1:]
}

return path
}
Expand Down
6 changes: 6 additions & 0 deletions vault/logical_system_paths.go
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,12 @@ func (b *SystemBackend) internalPaths() []*framework.Path {
Type: framework.TypeString,
Description: "Context string appended to every operationId",
},
"generic_mount_paths": {
Type: framework.TypeBool,
Description: "Use generic mount paths",
Query: true,
Default: false,
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.ReadOperation: b.pathInternalOpenAPI,
Expand Down
Loading

0 comments on commit 1c1b8a5

Please sign in to comment.