From 3130010dc72c0ac46777dd1a380c3ee8df3ed0cd Mon Sep 17 00:00:00 2001 From: srinandan Date: Sat, 29 Jan 2022 17:02:28 -0800 Subject: [PATCH] FR: gen bundle from oas - part 2 --- bundlegen/generateapi.go | 133 ++++++++++++++++++--------- bundlegen/policies/policies.go | 13 ++- bundlegen/proxybundle/proxybundle.go | 20 ++-- cmd/apis/crtapi.go | 4 + go.mod | 2 +- go.sum | 2 + 6 files changed, 118 insertions(+), 56 deletions(-) diff --git a/bundlegen/generateapi.go b/bundlegen/generateapi.go index 20c1f146..5ed8e906 100644 --- a/bundlegen/generateapi.go +++ b/bundlegen/generateapi.go @@ -30,13 +30,34 @@ import ( ) type pathDetailDef struct { - OperationID string - Description string - OAuthPolicy bool - APIKeyPoicy bool + OperationID string + Description string + SecurityScheme securitySchemesDef } -var generateOAuthPolicy, generateAPIKeyPolicy, generateSetTarget bool +type oAuthPolicyDef struct { + OAuthPolicyEnabled bool +} + +type securitySchemesListDef struct { + SecuritySchemes []securitySchemesDef +} + +type securitySchemesDef struct { + SchemeName string + OAuthPolicy oAuthPolicyDef + APIKeyPolicy apiKeyPolicyDef +} + +type apiKeyPolicyDef struct { + APIKeyPolicyEnabled bool + APIKeyLocation string + APIKeyName string +} + +var generateSetTarget bool + +var securitySchemesList = securitySchemesListDef{} var doc *openapi3.T @@ -126,6 +147,9 @@ func GenerateAPIProxyDefFromOAS(name string, oasDocName string, skipPolicy bool, return fmt.Errorf("Open API document not loaded") } + //load security schemes + loadSecurityRequirements(doc.Components.SecuritySchemes) + apiproxy.SetDisplayName(name) if doc.Info != nil { if doc.Info.Description != "" { @@ -166,6 +190,15 @@ func GenerateAPIProxyDefFromOAS(name string, oasDocName string, skipPolicy bool, proxies.NewProxyEndpoint(u.Path) + //add any preflow security schemes + if securityScheme := getSecurityRequirements(doc.Security); securityScheme.SchemeName != "" { + if securityScheme.APIKeyPolicy.APIKeyPolicyEnabled { + proxies.AddStepToPreFlowRequest("Verify-API-Key-" + securityScheme.SchemeName) + } else if securityScheme.OAuthPolicy.OAuthPolicyEnabled { + apiproxy.AddPolicy("OAuth-v20-1") + } + } + if addCORS { proxies.AddStepToPreFlowRequest("Add-CORS") apiproxy.AddPolicy("Add-CORS") @@ -179,12 +212,12 @@ func GenerateAPIProxyDefFromOAS(name string, oasDocName string, skipPolicy bool, return err } - if GenerateAPIKeyPolicy() { - apiproxy.AddPolicy("Verify-API-Key-1") - } - - if GenerateOAuthPolicy() { - apiproxy.AddPolicy("OAuth-v20-1") + for _, securityScheme := range securitySchemesList.SecuritySchemes { + if securityScheme.APIKeyPolicy.APIKeyPolicyEnabled { + apiproxy.AddPolicy("Verify-API-Key-" + securityScheme.SchemeName) + } else if securityScheme.OAuthPolicy.OAuthPolicyEnabled { + apiproxy.AddPolicy("OAuth-v20-1") + } } return nil @@ -215,7 +248,7 @@ func GetHTTPMethod(pathItem *openapi3.PathItem, keyPath string) map[string]pathD } if pathItem.Get.Security != nil { securityRequirements := []openapi3.SecurityRequirement(*pathItem.Get.Security) - getPathDetail.OAuthPolicy, getPathDetail.APIKeyPoicy = getSecurityRequirements(securityRequirements) + getPathDetail.SecurityScheme = getSecurityRequirements(securityRequirements) } pathMap["get"] = getPathDetail } @@ -232,7 +265,7 @@ func GetHTTPMethod(pathItem *openapi3.PathItem, keyPath string) map[string]pathD } if pathItem.Post.Security != nil { securityRequirements := []openapi3.SecurityRequirement(*pathItem.Post.Security) - postPathDetail.OAuthPolicy, postPathDetail.APIKeyPoicy = getSecurityRequirements(securityRequirements) + postPathDetail.SecurityScheme = getSecurityRequirements(securityRequirements) } pathMap["post"] = postPathDetail } @@ -249,7 +282,7 @@ func GetHTTPMethod(pathItem *openapi3.PathItem, keyPath string) map[string]pathD } if pathItem.Put.Security != nil { securityRequirements := []openapi3.SecurityRequirement(*pathItem.Put.Security) - putPathDetail.OAuthPolicy, putPathDetail.APIKeyPoicy = getSecurityRequirements(securityRequirements) + putPathDetail.SecurityScheme = getSecurityRequirements(securityRequirements) } pathMap["put"] = putPathDetail } @@ -266,7 +299,7 @@ func GetHTTPMethod(pathItem *openapi3.PathItem, keyPath string) map[string]pathD } if pathItem.Patch.Security != nil { securityRequirements := []openapi3.SecurityRequirement(*pathItem.Patch.Security) - patchPathDetail.OAuthPolicy, patchPathDetail.APIKeyPoicy = getSecurityRequirements(securityRequirements) + patchPathDetail.SecurityScheme = getSecurityRequirements(securityRequirements) } pathMap["patch"] = patchPathDetail } @@ -283,7 +316,7 @@ func GetHTTPMethod(pathItem *openapi3.PathItem, keyPath string) map[string]pathD } if pathItem.Delete.Security != nil { securityRequirements := []openapi3.SecurityRequirement(*pathItem.Delete.Security) - deletePathDetail.OAuthPolicy, deletePathDetail.APIKeyPoicy = getSecurityRequirements(securityRequirements) + deletePathDetail.SecurityScheme = getSecurityRequirements(securityRequirements) } pathMap["delete"] = deletePathDetail } @@ -335,13 +368,12 @@ func GenerateFlows(paths openapi3.Paths) (err error) { pathMap := GetHTTPMethod(paths[keyPath], keyPath) for method, pathDetail := range pathMap { proxies.AddFlow(pathDetail.OperationID, replacePathWithWildCard(keyPath), method, pathDetail.Description) - if pathDetail.OAuthPolicy { + if pathDetail.SecurityScheme.OAuthPolicy.OAuthPolicyEnabled { if err = proxies.AddStepToFlowRequest("OAuth-v20-1", pathDetail.OperationID); err != nil { return err } - } - if pathDetail.APIKeyPoicy { - if err = proxies.AddStepToFlowRequest("Verify-API-Key-1", pathDetail.OperationID); err != nil { + } else if pathDetail.SecurityScheme.APIKeyPolicy.APIKeyPolicyEnabled { + if err = proxies.AddStepToFlowRequest("Verify-API-Key-"+pathDetail.SecurityScheme.SchemeName, pathDetail.OperationID); err != nil { return err } } @@ -350,14 +382,6 @@ func GenerateFlows(paths openapi3.Paths) (err error) { return nil } -func GenerateOAuthPolicy() bool { - return generateOAuthPolicy -} - -func GenerateAPIKeyPolicy() bool { - return generateAPIKeyPolicy -} - func GenerateSetTargetPolicy() bool { return generateSetTarget } @@ -371,27 +395,52 @@ func replacePathWithWildCard(keyPath string) string { } } -func getSecurityType(name string) (oauth bool, apikey bool) { - for schemeName, securityScheme := range doc.Components.SecuritySchemes { - if schemeName == name { - if securityScheme.Value.Type == "oauth2" { - generateOAuthPolicy = true - return true, false - } - if securityScheme.Value.Type == "apiKey" { - generateAPIKeyPolicy = true - return false, true - } +func loadSecurityType(secSchemeName string, securityScheme openapi3.SecuritySchemeRef) (secScheme securitySchemesDef) { + secScheme = securitySchemesDef{} + apiKeyPolicy := apiKeyPolicyDef{} + oAuthPolicy := oAuthPolicyDef{} + + if securityScheme.Value.Type == "oauth2" { + secScheme.SchemeName = secSchemeName + oAuthPolicy.OAuthPolicyEnabled = true + apiKeyPolicy.APIKeyPolicyEnabled = false + secScheme.OAuthPolicy = oAuthPolicy + } else if securityScheme.Value.Type == "apiKey" { + secScheme.SchemeName = secSchemeName + apiKeyPolicy.APIKeyPolicyEnabled = true + oAuthPolicy.OAuthPolicyEnabled = false + apiKeyPolicy.APIKeyLocation = securityScheme.Value.In + apiKeyPolicy.APIKeyName = securityScheme.Value.Name + secScheme.APIKeyPolicy = apiKeyPolicy + } + + return secScheme +} + +func getSecurityType(secName string) securitySchemesDef { + for _, securityScheme := range securitySchemesList.SecuritySchemes { + if securityScheme.SchemeName == secName { + return securityScheme } } - return false, false + return securitySchemesDef{} } -func getSecurityRequirements(securityRequirements []openapi3.SecurityRequirement) (oauth bool, apikey bool) { +func getSecurityRequirements(securityRequirements []openapi3.SecurityRequirement) securitySchemesDef { for _, secReq := range securityRequirements { for secReqName := range secReq { return getSecurityType(secReqName) } } - return false, false + return securitySchemesDef{} +} + +func loadSecurityRequirements(securitySchemes openapi3.SecuritySchemes) { + for secSchemeName, secScheme := range securitySchemes { + securitySchemesList.SecuritySchemes = append(securitySchemesList.SecuritySchemes, loadSecurityType(secSchemeName, *secScheme)) + } +} + +func GetSecuritySchemesList() []securitySchemesDef { + return securitySchemesList.SecuritySchemes } diff --git a/bundlegen/policies/policies.go b/bundlegen/policies/policies.go index 32037b48..85c8cdbd 100644 --- a/bundlegen/policies/policies.go +++ b/bundlegen/policies/policies.go @@ -29,7 +29,7 @@ var oasPolicyTemplate = ` var verifyApiKeyPolicy = ` - Verify API Key-1 + Verify-API-Key-1 ` @@ -72,8 +72,15 @@ func AddOpenAPIValidatePolicy(name string) string { return replaceTemplateWithPolicy(name) } -func AddVerifyApiKeyPolicy() string { - return verifyApiKeyPolicy +func AddVerifyApiKeyPolicy(location string, policyName string, keyName string) string { + var apiKeyLocation string + if location == "query" { + apiKeyLocation = "request.queryparam." + keyName + } else { + apiKeyLocation = "request.header." + keyName + } + tmp := strings.Replace(verifyApiKeyPolicy, "request.queryparam.apikey", apiKeyLocation, -1) + return strings.Replace(tmp, "Verify-API-Key-1", "Verify-API-Key-"+policyName, -1) } func AddOAuth2Policy() string { diff --git a/bundlegen/proxybundle/proxybundle.go b/bundlegen/proxybundle/proxybundle.go index 9d27bb56..5787ed75 100644 --- a/bundlegen/proxybundle/proxybundle.go +++ b/bundlegen/proxybundle/proxybundle.go @@ -107,17 +107,17 @@ func GenerateAPIProxyBundle(name string, content string, fileName string, resour } } - //add oauth policy - if genapi.GenerateOAuthPolicy() { - if err = writeXMLData(policiesDirPath+string(os.PathSeparator)+"OAuth-v20-1.xml", policies.AddOAuth2Policy()); err != nil { - return err + //add security policies + for _, securityScheme := range genapi.GetSecuritySchemesList() { + if securityScheme.APIKeyPolicy.APIKeyPolicyEnabled { + if err = writeXMLData(policiesDirPath+string(os.PathSeparator)+"Verify-API-Key-"+securityScheme.SchemeName+".xml", policies.AddVerifyApiKeyPolicy(securityScheme.APIKeyPolicy.APIKeyLocation, securityScheme.SchemeName, securityScheme.APIKeyPolicy.APIKeyName)); err != nil { + return err + } } - } - - //add api key policy - if genapi.GenerateAPIKeyPolicy() { - if err = writeXMLData(policiesDirPath+string(os.PathSeparator)+"Verify-API-Key-1.xml", policies.AddVerifyApiKeyPolicy()); err != nil { - return err + if securityScheme.OAuthPolicy.OAuthPolicyEnabled { + if err = writeXMLData(policiesDirPath+string(os.PathSeparator)+"OAuth-v20-1.xml", policies.AddOAuth2Policy()); err != nil { + return err + } } } diff --git a/cmd/apis/crtapi.go b/cmd/apis/crtapi.go index b538a30b..f4eb7108 100644 --- a/cmd/apis/crtapi.go +++ b/cmd/apis/crtapi.go @@ -100,6 +100,7 @@ var CreateCmd = &cobra.Command{ return err } + //Generate the apiproxy struct err = bundle.GenerateAPIProxyDefFromOAS(name, oasDocName, skipPolicy, @@ -108,10 +109,12 @@ var CreateCmd = &cobra.Command{ oasGoogleIdTokenAudLiteral, oasGoogleIdTokenAudRef, oasTargetUrlRef) + if err != nil { return err } + //Create the API proxy bundle err = proxybundle.GenerateAPIProxyBundle(name, string(content), oasDocName, @@ -122,6 +125,7 @@ var CreateCmd = &cobra.Command{ oasGoogleIdTokenAudLiteral, oasGoogleIdTokenAudRef, oasTargetUrlRef) + if err != nil { return err } diff --git a/go.mod b/go.mod index 4dfbdbbd..33e32123 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/srinandan/apigeecli go 1.16 require ( - github.com/getkin/kin-openapi v0.83.0 + github.com/getkin/kin-openapi v0.88.0 github.com/ghodss/yaml v1.0.0 github.com/google/go-github v17.0.0+incompatible github.com/google/go-querystring v1.1.0 // indirect diff --git a/go.sum b/go.sum index fe3b10c8..41f6e43c 100644 --- a/go.sum +++ b/go.sum @@ -71,6 +71,8 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/getkin/kin-openapi v0.83.0 h1:qQbfSsapSPuRS73xhElJ85bWFo2REHNXBXAQ1kqqlCE= github.com/getkin/kin-openapi v0.83.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= +github.com/getkin/kin-openapi v0.88.0 h1:BjJ2JERWJbYE1o1RGEj/5LmR5qw7ecfl3O3su4ImR+0= +github.com/getkin/kin-openapi v0.88.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=