From 90192a79e1ea6993bdb707c5775e7187728f1e24 Mon Sep 17 00:00:00 2001 From: SLahiruC <40932779+slahirucd7@users.noreply.github.com> Date: Mon, 11 Dec 2023 20:43:41 +0530 Subject: [PATCH 1/2] initial commit to validate resource path content length --- adapter/config/default_config.go | 1 + adapter/config/types.go | 1 + adapter/internal/oasparser/model/open_api.go | 5 +++++ adapter/internal/oasparser/model/swagger.go | 17 ++++++++++++++--- .../oasparser/model/swagger_internal_test.go | 3 ++- adapter/internal/oasparser/model/types.go | 8 ++++++++ 6 files changed, 31 insertions(+), 4 deletions(-) diff --git a/adapter/config/default_config.go b/adapter/config/default_config.go index 3302fe23bf..06ba5a8e75 100644 --- a/adapter/config/default_config.go +++ b/adapter/config/default_config.go @@ -69,6 +69,7 @@ var defaultConfig = &Config{ SecuredListenerPort: 9095, ClusterTimeoutInSeconds: 20, EnforcerResponseTimeoutInSeconds: 20, + MaximumResourcePathLengthInKB: -1, KeyStore: keystore{ KeyPath: "/home/wso2/security/keystore/mg.key", CertPath: "/home/wso2/security/keystore/mg.pem", diff --git a/adapter/config/types.go b/adapter/config/types.go index f56b1145d8..8905a94c0b 100644 --- a/adapter/config/types.go +++ b/adapter/config/types.go @@ -118,6 +118,7 @@ type envoy struct { Upstream envoyUpstream Connection connection RateLimit rateLimit + MaximumResourcePathLengthInKB int16 } type connectionTimeouts struct { diff --git a/adapter/internal/oasparser/model/open_api.go b/adapter/internal/oasparser/model/open_api.go index 05a39ac96b..64a461e571 100644 --- a/adapter/internal/oasparser/model/open_api.go +++ b/adapter/internal/oasparser/model/open_api.go @@ -27,6 +27,7 @@ import ( "github.com/getkin/kin-openapi/openapi3" "github.com/google/uuid" + "github.com/wso2/product-microgateway/adapter/config" logger "github.com/wso2/product-microgateway/adapter/internal/loggers" ) @@ -130,7 +131,11 @@ func setResourcesOpenAPI(openAPI openapi3.Swagger) ([]*Resource, error) { // resource level if vendor ext is not present at each resource level. val, found := resolveDisableSecurity(openAPI.ExtensionProps) if openAPI.Paths != nil { + conf, _ := config.ReadConfigs() for path, pathItem := range openAPI.Paths { + if conf.Envoy.MaximumResourcePathLengthInKB != -1 && (isResourcePathLimitExceeds(path, int(conf.Envoy.MaximumResourcePathLengthInKB))) { + return nil, errors.New("The path " + path + " exceeds maximum allowed length") + } // Checks for resource level security. (security is disabled in resource level using x-wso2-disable-security extension) isResourceLvlSecurityDisabled, foundInResourceLevel := resolveDisableSecurity(pathItem.ExtensionProps) methodsArray := make([]*Operation, len(pathItem.Operations())) diff --git a/adapter/internal/oasparser/model/swagger.go b/adapter/internal/oasparser/model/swagger.go index 919dd75586..805aaeb5e6 100644 --- a/adapter/internal/oasparser/model/swagger.go +++ b/adapter/internal/oasparser/model/swagger.go @@ -22,6 +22,8 @@ import ( "github.com/go-openapi/spec" "github.com/google/uuid" + + "github.com/wso2/product-microgateway/adapter/config" logger "github.com/wso2/product-microgateway/adapter/internal/loggers" ) @@ -44,7 +46,11 @@ func (swagger *MgwSwagger) SetInfoSwagger(swagger2 spec.Swagger) error { swagger.vendorExtensions = swagger2.VendorExtensible.Extensions swagger.securityScheme = setSecurityDefinitions(swagger2) swagger.security = swagger2.Security - swagger.resources = setResourcesSwagger(swagger2) + parsedEndpoints, epParsingError := setResourcesSwagger(swagger2) + if epParsingError != nil { + return errors.New("one of the resource paths exceeds maximum allowed content length") + } + swagger.resources = parsedEndpoints swagger.apiType = HTTP swagger.xWso2Basepath = swagger2.BasePath // According to the definition, multiple schemes can be mentioned. Since the microgateway can assign only one scheme @@ -80,13 +86,18 @@ func (swagger *MgwSwagger) SetInfoSwagger(swagger2 spec.Swagger) error { } // setResourcesSwagger sets swagger (openapi v2) paths as mgwSwagger resources. -func setResourcesSwagger(swagger2 spec.Swagger) []*Resource { +func setResourcesSwagger(swagger2 spec.Swagger) ([]*Resource, error) { var resources []*Resource // Check if the "x-wso2-disable-security" vendor ext is present at the API level. // If API level vendor ext is present, then the same key:value should be added to // resourve level, if it's not present at resource level using "addResourceLevelDisableSecurity" if swagger2.Paths != nil { + conf, _ := config.ReadConfigs() for path, pathItem := range swagger2.Paths.Paths { + if conf.Envoy.MaximumResourcePathLengthInKB != -1 && + isResourcePathLimitExceeds(path, int(conf.Envoy.MaximumResourcePathLengthInKB)) { + return nil, errors.New("The path " + path + " exceeds maximum allowed length") + } disableSecurity, found := swagger2.VendorExtensible.Extensions.GetBool(xWso2DisableSecurity) // Checks for resource level security, if security is disabled in resource level, // below code segment will override above two variable values (disableSecurity & found) @@ -161,7 +172,7 @@ func setResourcesSwagger(swagger2 spec.Swagger) []*Resource { } } } - return SortResources(resources) + return SortResources(resources), nil } // Sets security definitions defined in swagger 2 format. diff --git a/adapter/internal/oasparser/model/swagger_internal_test.go b/adapter/internal/oasparser/model/swagger_internal_test.go index e6d52f4794..8af6d51277 100644 --- a/adapter/internal/oasparser/model/swagger_internal_test.go +++ b/adapter/internal/oasparser/model/swagger_internal_test.go @@ -128,7 +128,8 @@ func TestSetResourcesSwagger(t *testing.T) { }, } for _, item := range dataItems { - resultResources := setResourcesSwagger(item.input) + parsedResources, _ := setResourcesSwagger(item.input) + resultResources := parsedResources if item.result != nil { assert.Equal(t, item.result[0].path, resultResources[0].GetPath(), item.message) resultResources[0].GetMethod()[0].iD = item.result[0].methods[0].iD diff --git a/adapter/internal/oasparser/model/types.go b/adapter/internal/oasparser/model/types.go index 7ee2fb265b..d394cf968a 100644 --- a/adapter/internal/oasparser/model/types.go +++ b/adapter/internal/oasparser/model/types.go @@ -349,3 +349,11 @@ func createDefaultAPIYaml() APIYaml { }, } } + +func isResourcePathLimitExceeds(path string, maximumAllowedResourceLength int) bool { + strLength := len(path) + if float32(strLength)/1024 > float32(maximumAllowedResourceLength) { + return true + } + return false +} From 483694db0f2008d7b66ae56988b0ec3f8981d19d Mon Sep 17 00:00:00 2001 From: SLahiruC <40932779+slahirucd7@users.noreply.github.com> Date: Mon, 11 Dec 2023 20:52:44 +0530 Subject: [PATCH 2/2] minor improvements minor improvement minor improvement --- adapter/internal/oasparser/model/open_api.go | 5 +++-- adapter/internal/oasparser/model/swagger.go | 11 +++++------ resources/conf/config.toml.template | 2 ++ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/adapter/internal/oasparser/model/open_api.go b/adapter/internal/oasparser/model/open_api.go index 64a461e571..392d6f4c0b 100644 --- a/adapter/internal/oasparser/model/open_api.go +++ b/adapter/internal/oasparser/model/open_api.go @@ -133,8 +133,9 @@ func setResourcesOpenAPI(openAPI openapi3.Swagger) ([]*Resource, error) { if openAPI.Paths != nil { conf, _ := config.ReadConfigs() for path, pathItem := range openAPI.Paths { - if conf.Envoy.MaximumResourcePathLengthInKB != -1 && (isResourcePathLimitExceeds(path, int(conf.Envoy.MaximumResourcePathLengthInKB))) { - return nil, errors.New("The path " + path + " exceeds maximum allowed length") + if conf.Envoy.MaximumResourcePathLengthInKB != -1 && + isResourcePathLimitExceeds(path, int(conf.Envoy.MaximumResourcePathLengthInKB)) { + return nil, errors.New("path: " + path + " exceeds maximum allowed length") } // Checks for resource level security. (security is disabled in resource level using x-wso2-disable-security extension) isResourceLvlSecurityDisabled, foundInResourceLevel := resolveDisableSecurity(pathItem.ExtensionProps) diff --git a/adapter/internal/oasparser/model/swagger.go b/adapter/internal/oasparser/model/swagger.go index 805aaeb5e6..b19d1f38a4 100644 --- a/adapter/internal/oasparser/model/swagger.go +++ b/adapter/internal/oasparser/model/swagger.go @@ -22,7 +22,6 @@ import ( "github.com/go-openapi/spec" "github.com/google/uuid" - "github.com/wso2/product-microgateway/adapter/config" logger "github.com/wso2/product-microgateway/adapter/internal/loggers" ) @@ -46,11 +45,11 @@ func (swagger *MgwSwagger) SetInfoSwagger(swagger2 spec.Swagger) error { swagger.vendorExtensions = swagger2.VendorExtensible.Extensions swagger.securityScheme = setSecurityDefinitions(swagger2) swagger.security = swagger2.Security - parsedEndpoints, epParsingError := setResourcesSwagger(swagger2) - if epParsingError != nil { - return errors.New("one of the resource paths exceeds maximum allowed content length") + parsedResources, resourceParsingError := setResourcesSwagger(swagger2) + if resourceParsingError != nil { + return errors.New("one of the resource paths in the swagger definition exceeds maximum allowed content length") } - swagger.resources = parsedEndpoints + swagger.resources = parsedResources swagger.apiType = HTTP swagger.xWso2Basepath = swagger2.BasePath // According to the definition, multiple schemes can be mentioned. Since the microgateway can assign only one scheme @@ -96,7 +95,7 @@ func setResourcesSwagger(swagger2 spec.Swagger) ([]*Resource, error) { for path, pathItem := range swagger2.Paths.Paths { if conf.Envoy.MaximumResourcePathLengthInKB != -1 && isResourcePathLimitExceeds(path, int(conf.Envoy.MaximumResourcePathLengthInKB)) { - return nil, errors.New("The path " + path + " exceeds maximum allowed length") + return nil, errors.New("path: " + path + " exceeds maximum allowed length") } disableSecurity, found := swagger2.VendorExtensible.Extensions.GetBool(xWso2DisableSecurity) // Checks for resource level security, if security is disabled in resource level, diff --git a/resources/conf/config.toml.template b/resources/conf/config.toml.template index 0b911dcb9b..856b537241 100644 --- a/resources/conf/config.toml.template +++ b/resources/conf/config.toml.template @@ -84,6 +84,8 @@ sandboxVhost = "sandbox.host" systemHost = "localhost" # Hostname for API Resources exposed within the cluster (eg: /.wellknown/jwks and /testkey) internalServiceHost = "localhost" + # Allowed maximum resource path content size in KB + maximumResourcePathLengthInKB = -1 # Configurations of key store used in Choreo Connect Router [router.keystore]