diff --git a/adapter/go.mod b/adapter/go.mod index 191cdd010..8e64f8225 100644 --- a/adapter/go.mod +++ b/adapter/go.mod @@ -1,6 +1,6 @@ module github.com/wso2/apk/adapter -go 1.20 +go 1.21 require ( github.com/envoyproxy/go-control-plane v0.12.0 @@ -16,7 +16,6 @@ require ( golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb google.golang.org/grpc v1.62.0 google.golang.org/protobuf v1.32.0 - gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.29.2 k8s.io/apimachinery v0.29.2 k8s.io/client-go v0.29.2 @@ -82,6 +81,7 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiextensions-apiserver v0.29.2 // indirect k8s.io/component-base v0.29.2 // indirect diff --git a/adapter/go.sum b/adapter/go.sum index ee255b712..8df079e2a 100644 --- a/adapter/go.sum +++ b/adapter/go.sum @@ -30,6 +30,7 @@ github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/Ir github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= +github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.8.0 h1:lRj6N9Nci7MvzrXuX6HFzU8XjmhPiXPlsKEy1u0KQro= github.com/evanphx/json-patch/v5 v5.8.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= @@ -85,6 +86,7 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -124,8 +126,10 @@ github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGy github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/shirou/gopsutil/v3 v3.24.2 h1:kcR0erMbLg5/3LcInpw0X/rrPSqq4CDPyI6A6ZRC18Y= github.com/shirou/gopsutil/v3 v3.24.2/go.mod h1:tSg/594BcA+8UdQU2XcW803GWYgdtauFFPgJCJKZlVk= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= @@ -159,6 +163,7 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= diff --git a/adapter/internal/oasparser/constants/constants.go b/adapter/internal/oasparser/constants/constants.go index df863dc5a..7bd890464 100644 --- a/adapter/internal/oasparser/constants/constants.go +++ b/adapter/internal/oasparser/constants/constants.go @@ -71,9 +71,6 @@ const ( // operational policy field names const ( - ActionHeaderAdd string = "SET_HEADER" - ActionHeaderRemove string = "REMOVE_HEADER" - ActionRewriteMethod string = "REWRITE_RESOURCE_METHOD" ActionInterceptorService string = "CALL_INTERCEPTOR_SERVICE" ActionRewritePath string = "REWRITE_RESOURCE_PATH" @@ -82,7 +79,6 @@ const ( RewritePathResourcePath string = "resourcePath" RewritePathType string = "rewritePathType" - InterceptorServiceURL string = "interceptorServiceURL" InterceptorEndpoints string = "interceptorEndpoints" InterceptorServiceIncludes string = "includes" IncludeQueryParams string = "includeQueryParams" diff --git a/adapter/internal/oasparser/envoyconf/routes_with_clusters.go b/adapter/internal/oasparser/envoyconf/routes_with_clusters.go index 4998cca17..38369c4a7 100644 --- a/adapter/internal/oasparser/envoyconf/routes_with_clusters.go +++ b/adapter/internal/oasparser/envoyconf/routes_with_clusters.go @@ -896,34 +896,10 @@ func createRoutes(params *routeCreateParams) (routes []*routev3.Route, err error var responseHeadersToRemove []string var pathRewriteConfig *envoy_type_matcherv3.RegexMatchAndSubstitute - hasMethodRewritePolicy := false - var newMethod string - // Policies - for request flow for _, requestPolicy := range operation.GetPolicies().Request { logger.LoggerOasparser.Debug("Adding request flow policies for ", resourcePath, operation.GetMethod()) switch requestPolicy.Action { - - case constants.ActionHeaderAdd: - logger.LoggerOasparser.Debugf("Adding %s policy to request flow for %s %s", - constants.ActionHeaderAdd, resourcePath, operation.GetMethod()) - requestHeaderToAdd, err := generateHeaderToAddRouteConfig(requestPolicy.Parameters) - if err != nil { - return nil, fmt.Errorf("error adding request policy %s to operation %s of resource %s."+ - " %v", requestPolicy.Action, operation.GetMethod(), resourcePath, err) - } - requestHeadersToAdd = append(requestHeadersToAdd, requestHeaderToAdd) - - case constants.ActionHeaderRemove: - logger.LoggerOasparser.Debugf("Adding %s policy to request flow for %s %s", - constants.ActionHeaderRemove, resourcePath, operation.GetMethod()) - requestHeaderToRemove, err := generateHeaderToRemoveString(requestPolicy.Parameters) - if err != nil { - return nil, fmt.Errorf("error adding request policy %s to operation %s of resource %s."+ - " %v", requestPolicy.Action, operation.GetMethod(), resourcePath, err) - } - requestHeadersToRemove = append(requestHeadersToRemove, requestHeaderToRemove) - case constants.ActionRewritePath: logger.LoggerOasparser.Debugf("Adding %s policy to request flow for %s %s", constants.ActionRewritePath, resourcePath, operation.GetMethod()) @@ -936,105 +912,23 @@ func createRoutes(params *routeCreateParams) (routes []*routev3.Route, err error return nil, errors.New(errMsg) } pathRewriteConfig = regexRewrite - - case constants.ActionRewriteMethod: - logger.LoggerOasparser.Debugf("Adding %s policy to request flow for %s %s", - constants.ActionRewriteMethod, resourcePath, operation.GetMethod()) - hasMethodRewritePolicy, err = isMethodRewrite(resourcePath, operation.GetMethod(), requestPolicy.Parameters) - if err != nil { - return nil, err - } - if !hasMethodRewritePolicy { - continue - } - newMethod, err = getRewriteMethod(resourcePath, operation.GetMethod(), requestPolicy.Parameters) - if err != nil { - return nil, err - } - } - } - - // Policies - for response flow - for _, responsePolicy := range operation.GetPolicies().Response { - logger.LoggerOasparser.Debug("Adding response flow policies for ", resourcePath, operation.GetMethod()) - switch responsePolicy.Action { - - case constants.ActionHeaderAdd: - logger.LoggerOasparser.Debugf("Adding %s policy to response flow for %s %s", - constants.ActionHeaderAdd, resourcePath, operation.GetMethod()) - responseHeaderToAdd, err := generateHeaderToAddRouteConfig(responsePolicy.Parameters) - if err != nil { - return nil, fmt.Errorf("error adding response policy %s to operation %s of resource %s."+ - " %v", responsePolicy.Action, operation.GetMethod(), resourcePath, err) - } - responseHeadersToAdd = append(responseHeadersToAdd, responseHeaderToAdd) - - case constants.ActionHeaderRemove: - logger.LoggerOasparser.Debugf("Adding %s policy to response flow for %s %s", - constants.ActionHeaderRemove, resourcePath, operation.GetMethod()) - responseHeaderToRemove, err := generateHeaderToRemoveString(responsePolicy.Parameters) - if err != nil { - return nil, fmt.Errorf("error adding response policy %s to operation %s of resource %s."+ - " %v", responsePolicy.Action, operation.GetMethod(), resourcePath, err) - } - responseHeadersToRemove = append(responseHeadersToRemove, responseHeaderToRemove) } } - // TODO: (suksw) preserve header key case? - if hasMethodRewritePolicy { - logger.LoggerOasparser.Debugf("Creating two routes to support method rewrite for %s %s. New method: %s", - resourcePath, operation.GetMethod(), newMethod) - match1 := generateRouteMatch(routePath) - match1.Headers = generateHTTPMethodMatcher(operation.GetMethod(), clusterName) - match2 := generateRouteMatch(routePath) - match2.Headers = generateHTTPMethodMatcher(newMethod, clusterName) - - //- external routes only accept requests if metadata "method-rewrite" is null - //- external routes adds the metadata "method-rewrite" - //- internal routes only accept requests if metadata "method-rewrite" matches - // metadataValue _to_ - match1.DynamicMetadata = generateMetadataMatcherForExternalRoutes() - metadataValue := operation.GetMethod() + "_to_" + newMethod - match2.DynamicMetadata = generateMetadataMatcherForInternalRoutes(metadataValue) - - action1 := generateRouteAction(apiType, routeConfig, rateLimitPolicyCriteria) - action2 := generateRouteAction(apiType, routeConfig, rateLimitPolicyCriteria) - - // Create route1 for current method. - // Do not add policies to route config. Send via enforcer - route1 := generateRouteConfig(xWso2Basepath+operation.GetMethod(), match1, action1, nil, decorator, perRouteFilterConfigs, - nil, nil, nil, nil) - - // Create route2 for new method. - // Add all policies to route config. Do not send via enforcer. - if pathRewriteConfig != nil { - action2.Route.RegexRewrite = pathRewriteConfig - } else { - action2.Route.RegexRewrite = generateRegexMatchAndSubstitute(routePath, resourcePath, pathMatchType) - } - configToSkipEnforcer := generateFilterConfigToSkipEnforcer() - route2 := generateRouteConfig(xWso2Basepath, match2, action2, nil, decorator, configToSkipEnforcer, - requestHeadersToAdd, requestHeadersToRemove, responseHeadersToAdd, responseHeadersToRemove) - - routes = append(routes, route1) - routes = append(routes, route2) + logger.LoggerOasparser.Debug("Creating routes for resource with policies", resourcePath, operation.GetMethod()) + // create route for current method. Add policies to route config. Send via enforcer + action := generateRouteAction(apiType, routeConfig, rateLimitPolicyCriteria) + match := generateRouteMatch(routePath) + match.Headers = generateHTTPMethodMatcher(operation.GetMethod(), clusterName) + match.DynamicMetadata = generateMetadataMatcherForExternalRoutes() + if pathRewriteConfig != nil { + action.Route.RegexRewrite = pathRewriteConfig } else { - logger.LoggerOasparser.Debug("Creating routes for resource with policies", resourcePath, operation.GetMethod()) - // create route for current method. Add policies to route config. Send via enforcer - action := generateRouteAction(apiType, routeConfig, rateLimitPolicyCriteria) - match := generateRouteMatch(routePath) - match.Headers = generateHTTPMethodMatcher(operation.GetMethod(), clusterName) - match.DynamicMetadata = generateMetadataMatcherForExternalRoutes() - if pathRewriteConfig != nil { - action.Route.RegexRewrite = pathRewriteConfig - } else { - action.Route.RegexRewrite = generateRegexMatchAndSubstitute(routePath, resourcePath, pathMatchType) - } - route := generateRouteConfig(xWso2Basepath, match, action, nil, decorator, perRouteFilterConfigs, - requestHeadersToAdd, requestHeadersToRemove, responseHeadersToAdd, responseHeadersToRemove) - routes = append(routes, route) + action.Route.RegexRewrite = generateRegexMatchAndSubstitute(routePath, resourcePath, pathMatchType) } + route := generateRouteConfig(xWso2Basepath, match, action, nil, decorator, perRouteFilterConfigs, + requestHeadersToAdd, requestHeadersToRemove, responseHeadersToAdd, responseHeadersToRemove) + routes = append(routes, route) } } else { logger.LoggerOasparser.Debugf("Creating routes for resource : %s that has no policies", resourcePath) @@ -1410,55 +1304,6 @@ func generateSubstitutionString(resourcePath string, pathMatchType gwapiv1.PathM return resourceRegex } -func isMethodRewrite(resourcePath, method string, policyParams interface{}) (isMethodRewrite bool, err error) { - var paramsToRewriteMethod map[string]interface{} - var ok bool - if paramsToRewriteMethod, ok = policyParams.(map[string]interface{}); !ok { - return false, fmt.Errorf("error while processing policy parameter map for "+ - "request policy %s to operation %s of resource %s. Map: %v", - constants.ActionRewriteMethod, method, resourcePath, policyParams) - } - - currentMethod, exists := paramsToRewriteMethod[constants.CurrentMethod] - if !exists { - return true, nil - } - currentMethodString, _ := currentMethod.(string) - - if currentMethodString == "" { // the package text/template return this for keys that does not exist - return true, nil - } - - if currentMethodString != method { - return false, nil - } - return true, nil // currentMethodString == method -} - -func getRewriteMethod(resourcePath, method string, policyParams interface{}) (rewriteMethod string, err error) { - var paramsToRewriteMethod map[string]interface{} - var ok bool - if paramsToRewriteMethod, ok = policyParams.(map[string]interface{}); !ok { - return "", fmt.Errorf("error while processing policy parameter map for "+ - "request policy %s to operation %s of resource %s. Map: %v", - constants.ActionRewriteMethod, method, resourcePath, policyParams) - } - - updatedMethod, exists := paramsToRewriteMethod[constants.UpdatedMethod] - if !exists { - return "", fmt.Errorf("error adding request policy %s to operation %s of resource %s."+ - " Policy parameter updatedMethod not found", - constants.ActionRewriteMethod, method, resourcePath) - } - updatedMethodString, isString := updatedMethod.(string) - if !isString { - return "", fmt.Errorf("error adding request policy %s to operation %s of resource %s."+ - " Policy parameter updatedMethod is in incorrect format", constants.ActionRewriteMethod, - method, resourcePath) - } - return updatedMethodString, nil -} - func getUpgradeConfig(apiType string) []*routev3.RouteAction_UpgradeConfig { var upgradeConfig []*routev3.RouteAction_UpgradeConfig if apiType == constants.WS { diff --git a/adapter/internal/oasparser/model/adapter_internal_api.go b/adapter/internal/oasparser/model/adapter_internal_api.go index a8746a788..ad7805976 100644 --- a/adapter/internal/oasparser/model/adapter_internal_api.go +++ b/adapter/internal/oasparser/model/adapter_internal_api.go @@ -618,72 +618,6 @@ func (adapterInternalAPI *AdapterInternalAPI) SetInfoHTTPRouteCR(httpRoute *gwap 'Resource' in resource level RateLimitPolicies`, filter.ExtensionRef.Name) } } - case gwapiv1.HTTPRouteFilterRequestHeaderModifier: - for _, header := range filter.RequestHeaderModifier.Add { - policyParameters := make(map[string]interface{}) - policyParameters[constants.HeaderName] = string(header.Name) - policyParameters[constants.HeaderValue] = string(header.Value) - - policies.Request = append(policies.Request, Policy{ - PolicyName: string(gwapiv1.HTTPRouteFilterRequestHeaderModifier), - Action: constants.ActionHeaderAdd, - Parameters: policyParameters, - }) - } - for _, header := range filter.RequestHeaderModifier.Remove { - policyParameters := make(map[string]interface{}) - policyParameters[constants.HeaderName] = string(header) - - policies.Request = append(policies.Request, Policy{ - PolicyName: string(gwapiv1.HTTPRouteFilterRequestHeaderModifier), - Action: constants.ActionHeaderRemove, - Parameters: policyParameters, - }) - } - for _, header := range filter.RequestHeaderModifier.Set { - policyParameters := make(map[string]interface{}) - policyParameters[constants.HeaderName] = string(header.Name) - policyParameters[constants.HeaderValue] = string(header.Value) - - policies.Request = append(policies.Request, Policy{ - PolicyName: string(gwapiv1.HTTPRouteFilterRequestHeaderModifier), - Action: constants.ActionHeaderAdd, - Parameters: policyParameters, - }) - } - case gwapiv1.HTTPRouteFilterResponseHeaderModifier: - for _, header := range filter.ResponseHeaderModifier.Add { - policyParameters := make(map[string]interface{}) - policyParameters[constants.HeaderName] = string(header.Name) - policyParameters[constants.HeaderValue] = string(header.Value) - - policies.Response = append(policies.Response, Policy{ - PolicyName: string(gwapiv1.HTTPRouteFilterResponseHeaderModifier), - Action: constants.ActionHeaderAdd, - Parameters: policyParameters, - }) - } - for _, header := range filter.ResponseHeaderModifier.Remove { - policyParameters := make(map[string]interface{}) - policyParameters[constants.HeaderName] = string(header) - - policies.Response = append(policies.Response, Policy{ - PolicyName: string(gwapiv1.HTTPRouteFilterResponseHeaderModifier), - Action: constants.ActionHeaderRemove, - Parameters: policyParameters, - }) - } - for _, header := range filter.ResponseHeaderModifier.Set { - policyParameters := make(map[string]interface{}) - policyParameters[constants.HeaderName] = string(header.Name) - policyParameters[constants.HeaderValue] = string(header.Value) - - policies.Response = append(policies.Response, Policy{ - PolicyName: string(gwapiv1.HTTPRouteFilterResponseHeaderModifier), - Action: constants.ActionHeaderAdd, - Parameters: policyParameters, - }) - } } } resourceAPIPolicy = concatAPIPolicies(resourceAPIPolicy, nil) diff --git a/adapter/internal/oasparser/model/async_api.go b/adapter/internal/oasparser/model/async_api.go deleted file mode 100644 index 859d4ad2c..000000000 --- a/adapter/internal/oasparser/model/async_api.go +++ /dev/null @@ -1,222 +0,0 @@ -// /* -// * Copyright (c) 2022, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. -// * -// * Licensed under the Apache License, Version 2.0 (the "License"); -// * you may not use this file except in compliance with the License. -// * You may obtain a copy of the License at -// * -// * http://www.apache.org/licenses/LICENSE-2.0 -// * -// * Unless required by applicable law or agreed to in writing, software -// * distributed under the License is distributed on an "AS IS" BASIS, -// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// * See the License for the specific language governing permissions and -// * limitations under the License. -// * -// */ - -package model - -// import ( -// "encoding/json" -// "errors" -// "strings" - -// "github.com/wso2/apk/adapter/internal/loggers" -// "github.com/wso2/apk/adapter/internal/oasparser/constants" -// ) - -// // AsyncAPI is the struct for the AsyncAPI 2.0.0 definition -// type AsyncAPI struct { -// SpecVersion string `json:"asyncapi,omitempty"` -// ID string `json:"id,omitempty"` -// Info struct { -// Title string `json:"title,omitempty"` -// Version string `json:"version,omitempty"` -// } `json:"info,omitempty"` -// Servers struct { -// Production Server `json:"production,omitempty"` -// Sandbox Server `json:"sandbox,omitempty"` -// } `json:"servers,omitempty"` -// Channels map[string]ChannelItem `json:"channels,omitempty"` -// Components struct { -// Schemas map[string]interface{} `json:"schemas,omitempty"` -// Messages map[string]interface{} `json:"messages,omitempty"` -// SecuritySchemes map[string]SecurityScheme `json:"securitySchemes,omitempty"` -// } `json:"components,omitempty"` -// VendorExtensions map[string]interface{} `json:"-"` -// } - -// // Server object in AsyncAPI -// type Server struct { -// URL string `json:"url,omitempty"` -// Protocol string `json:"protocol,omitempty"` -// ProtocolVersion string `json:"protocolVersion,omitempty"` -// Variables map[string]interface{} `json:"variables,omitempty"` -// Security []map[string][]string `json:"security,omitempty"` -// Bindings map[string]interface{} `json:"bindings,omitempty"` -// } - -// // ChannelItem in AsyncAPI channels -// type ChannelItem struct { -// Ref string `json:"$ref,omitempty"` -// Subscribe interface{} `json:"subscribe,omitempty"` // TODO: (suksw) OperationAsync or $ref -// Publish interface{} `json:"publish,omitempty"` // TODO: (suksw) OperationAsync or $ref -// Parameters map[string]interface{} `json:"parameters,omitempty"` -// Bindings map[string]interface{} `json:"bindings,omitempty"` -// XAuthType string `json:"x-auth-type,omitempty"` -// XWso2DisableSecurity bool `json:"x-wso2-disable-security,omitempty"` -// } - -// // OperationAsync is the Operation object that includes the message object -// type OperationAsync struct { -// OperationID string `json:"operationId,omitempty"` -// Message struct { -// Headers string `json:"headers,omitempty"` -// Payload string `json:"payload,omitempty"` -// CorrelationID string `json:"correlationId,omitempty"` -// SchemaFormat string `json:"schemaFormat,omitempty"` -// ContentType string `json:"contentType,omitempty"` -// Name string `json:"name,omitempty"` -// Title string `json:"title,omitempty"` -// } -// } - -// // SetInfoAsyncAPI populates the AdapterInternalAPI object with information in asyncapi.yaml. -// func (swagger *AdapterInternalAPI) SetInfoAsyncAPI(asyncAPI AsyncAPI) error { -// swagger.vendorExtensions = asyncAPI.VendorExtensions -// swagger.disableSecurity = ResolveDisableSecurity(asyncAPI.VendorExtensions) -// swagger.securityScheme = asyncAPI.getSecuritySchemes() -// swagger.resources = asyncAPI.getResources() - -// if asyncAPI.Servers.Production.URL != "" { -// endpoint, err := getWebSocketEndpoint(asyncAPI.Servers.Production.URL) -// if err == nil { -// productionEndpoints := append([]Endpoint{}, *endpoint) -// swagger.productionEndpoints = generateEndpointCluster(constants.ProdClustersConfigNamePrefix, -// productionEndpoints, constants.LoadBalance) -// } else { -// return errors.New("error encountered when parsing the production endpoint for AsyncAPI") -// } -// } -// if asyncAPI.Servers.Sandbox.URL != "" { -// endpoint, err := getWebSocketEndpoint(asyncAPI.Servers.Sandbox.URL) -// if err == nil { -// sandboxEndpoints := append([]Endpoint{}, *endpoint) -// swagger.sandboxEndpoints = generateEndpointCluster(constants.SandClustersConfigNamePrefix, -// sandboxEndpoints, constants.LoadBalance) -// } else { -// return errors.New("error encountered when parsing the sandbox endpoint for AsyncAPI") -// } -// } -// return nil -// } - -// func (asyncAPI AsyncAPI) getSecuritySchemes() []SecurityScheme { -// securitySchemes := []SecurityScheme{} -// for key, securityScheme := range asyncAPI.Components.SecuritySchemes { -// securityScheme.DefinitionName = key -// securitySchemes = append(securitySchemes, securityScheme) -// } -// return securitySchemes -// } - -// func (asyncAPI AsyncAPI) getResources() []*Resource { -// resources := []*Resource{} -// for channel, channelItem := range asyncAPI.Channels { -// // ex: channel = /notify, channelItem = { Publish:map, Subscribe:map } -// var pubOrSubVendorExtensions map[string]interface{} - -// if channelItem.Publish != nil { -// pubOrSubVendorExtensions = channelItem.Publish.(map[string]interface{}) -// if channelItem.Subscribe != nil { -// loggers.LoggerOasparser.Warnf( -// "Both Publish and Subscribe types exists for the same topic. "+ -// "Prioritizing the extensions under type Publish for the topic %v.", channel) -// } -// } else if channelItem.Subscribe != nil { -// pubOrSubVendorExtensions = channelItem.Subscribe.(map[string]interface{}) -// } else { -// loggers.LoggerOasparser.Warnf( -// "The topic does not include a Publish or a Subscribe definition. Discarding the topic %v.", channel) -// continue -// } - -// if channelItem.XAuthType == "None" || channelItem.XWso2DisableSecurity { -// pubOrSubVendorExtensions[constants.XWso2DisableSecurity] = true -// } - -// security := getSecurityArray(pubOrSubVendorExtensions) -// operation := NewOperation("GET", security, pubOrSubVendorExtensions) -// // The path rewrite operation is applied from async-api definition. -// // (Where in REST API scenario, it is populated from api.yaml) -// populatePoliciesFromVendorExtensions(operation, pubOrSubVendorExtensions) -// var methodsArray []*Operation -// methodsArray = append(methodsArray, operation) - -// // we ignore other topic vendor extensions except x-auth-type and x-wso2-disable-security -// channelVendorExtensions := map[string]interface{}{} -// resource := unmarshalSwaggerResources(channel, methodsArray, channelVendorExtensions) -// resource.hasPolicies = true // to rewrite path depending on x-uri-mapping -// resources = append(resources, &resource) -// } - -// return SortResources(resources) -// } - -// func populatePoliciesFromVendorExtensions(operation *Operation, vendorExtensions map[string]interface{}) { -// var newResourcePath string -// policyParameters := make(map[string]interface{}) -// if uriMapping, found := vendorExtensions[constants.XUriMapping]; found { -// newResourcePath = uriMapping.(string) -// if strings.Contains(newResourcePath, "?") { -// newResourcePath = newResourcePath[:strings.Index(newResourcePath, "?")] -// } -// // URI Mapping parameter is only used when enforcer needs to map path parameters to query parameters. -// policyParameters[constants.XUriMapping] = uriMapping.(string) -// } else { -// newResourcePath = "/" -// } -// policyParameters[constants.RewritePathResourcePath] = newResourcePath -// policyParameters[constants.IncludeQueryParams] = true -// policy := Policy{ -// Action: constants.ActionRewritePath, -// Parameters: policyParameters, -// IsPassToEnforcer: supportedPoliciesMap[constants.ActionRewritePath].IsPassToEnforcer, -// } -// operation.policies = OperationPolicies{ -// Request: []Policy{policy}, -// } -// } - -// func getSecurityArray(vendorExtensions map[string]interface{}) (security []map[string][]string) { -// if vendorExtensions[constants.XScopes] != nil { -// securityItem := make(map[string][]string) -// rawScopes := vendorExtensions[constants.XScopes].([]interface{}) -// var scopes []string - -// for _, rawScope := range rawScopes { -// scopes = append(scopes, rawScope.(string)) -// } -// securityItem[constants.Oauth2TypeInOAS] = scopes -// security = append(security, securityItem) -// } -// return security -// } - -// func (asyncAPI AsyncAPI) unmarshallAPILevelVendorExtensions(b []byte) error { -// var apiDef map[string]interface{} -// if err := json.Unmarshal(b, &apiDef); err != nil { -// return errors.New("Error while unmarshalling API level vendor extensions." + err.Error()) -// } -// for key, value := range apiDef { -// keyl := strings.ToLower(key) -// if strings.HasPrefix(keyl, "x-") { -// if asyncAPI.VendorExtensions == nil { -// asyncAPI.VendorExtensions = map[string]interface{}{} -// } -// asyncAPI.VendorExtensions[key] = value -// } -// } -// return nil -// } diff --git a/adapter/internal/oasparser/model/policy.go b/adapter/internal/oasparser/model/policy.go index 5da42aae4..fc3a72e4e 100644 --- a/adapter/internal/oasparser/model/policy.go +++ b/adapter/internal/oasparser/model/policy.go @@ -17,10 +17,6 @@ package model -import ( - "fmt" -) - // OperationPolicies holds policies of the APIM operations type OperationPolicies struct { Request PolicyList `json:"request,omitempty"` @@ -39,9 +35,3 @@ type Policy struct { IsPassToEnforcer bool `json:"-"` // This is a meta value used in APK, not included in API YAML Parameters interface{} `json:"parameters,omitempty"` } - -// GetFullName returns the fully qualified name of the policy -// This should be equal to the policy spec/def file name -func (p *Policy) GetFullName() string { - return fmt.Sprintf("%s_%s", p.PolicyName, p.PolicyVersion) -} diff --git a/adapter/internal/oasparser/model/policy_container.go b/adapter/internal/oasparser/model/policy_container.go deleted file mode 100644 index 80d87a0d3..000000000 --- a/adapter/internal/oasparser/model/policy_container.go +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (c) 2022, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package model - -import ( - "bytes" - "fmt" - "regexp" - "text/template" - - "github.com/wso2/apk/adapter/internal/loggers" - logging "github.com/wso2/apk/adapter/internal/logging" - "gopkg.in/yaml.v2" -) - -var ( - // policyDefFuncMap is a map of functions used in policy definitions - policyDefFuncMap = template.FuncMap{ - // isParamExists checks the key is exists in the params map, this will not consider the value of the param - // if the go templated "{{ if .param }}" is used, that will consider the - // value of the param (if value is a zero value, it consider as not exists) - "isParamExists": func(m map[string]interface{}, key string) (ok bool) { - _, ok = m[key] - return - }, - } -) - -// PolicyFlow holds list of Policies in a operation (in one flow: In, Out or Fault) -type PolicyFlow string - -const ( - policyInFlow PolicyFlow = "request" - policyOutFlow PolicyFlow = "response" - policyFaultFlow PolicyFlow = "fault" -) - -// PolicyContainerMap maps PolicyName -> PolicyContainer -type PolicyContainerMap map[string]PolicyContainer - -// PolicyContainer holds the definition and specification of policy -type PolicyContainer struct { - Specification PolicySpecification - Definition PolicyDefinition -} - -// PolicySpecification holds policy specification from ./Policy/.yaml files -type PolicySpecification struct { - Type string `yaml:"type" json:"type"` - Version string `yaml:"version" json:"version"` - Data struct { - Name string `yaml:"name"` - Version string `yaml:"version"` - ApplicableFlows []string `yaml:"applicableFlows"` - SupportedGateways []string `yaml:"supportedGateways"` - SupportedAPITypes []string `yaml:"supportedApiTypes"` - MultipleAllowed bool `yaml:"multipleAllowed"` - PolicyAttributes []struct { - Name string `yaml:"name"` - ValidationRegex string `yaml:"validationRegex,omitempty"` - Type string `yaml:"type"` - DefaultValue string `yaml:"defaultValue"` - Required bool `yaml:"required,omitempty"` - } `yaml:"policyAttributes"` - } -} - -// PolicyDefinition holds the content of policy definition which is rendered from ./Policy/.gotmpl files -type PolicyDefinition struct { - Definition struct { - Action string `yaml:"action"` - Parameters map[string]interface{} `yaml:"parameters"` - } `yaml:"definition"` - RawData []byte `yaml:"-"` -} - -// GetFormattedOperationalPolicies returns formatted, policy from a user templated policy -// here, the struct swagger is only used for logging purpose, in case if we introduce logger context to get org ID, API ID, we can remove it from here -func (p PolicyContainerMap) GetFormattedOperationalPolicies(policies OperationPolicies, swagger *AdapterInternalAPI) (OperationPolicies, error) { - fmtPolicies := OperationPolicies{} - - for _, policy := range policies.Request { - if fmtPolicy, err := p.getFormattedPolicyFromTemplated(policy, policyInFlow, swagger); err == nil { - fmtPolicies.Request = append(fmtPolicies.Request, fmtPolicy) - loggers.LoggerOasparser.Debugf("Applying operation policy %q in request flow, for API %q in org %q, formatted policy %v", - policy.GetFullName(), swagger.GetID(), swagger.OrganizationID, fmtPolicy) - } else { - return fmtPolicies, err - } - } - - for _, policy := range policies.Response { - if fmtPolicy, err := p.getFormattedPolicyFromTemplated(policy, policyOutFlow, swagger); err == nil { - fmtPolicies.Response = append(fmtPolicies.Response, fmtPolicy) - loggers.LoggerOasparser.Debugf("Applying operation policy %q in response flow, for API %q in org %q, formatted policy %v", - policy.GetFullName(), swagger.GetID(), swagger.OrganizationID, fmtPolicy) - } else { - return fmtPolicies, err - } - } - - for _, policy := range policies.Fault { - if fmtPolicy, err := p.getFormattedPolicyFromTemplated(policy, policyFaultFlow, swagger); err == nil { - fmtPolicies.Fault = append(fmtPolicies.Fault, fmtPolicy) - loggers.LoggerOasparser.Debugf("Applying operation policy %q in fault flow, for API %q in org %q, formatted policy %v", - policy.GetFullName(), swagger.GetID(), swagger.OrganizationID, fmtPolicy) - } else { - return fmtPolicies, err - } - } - - return fmtPolicies, nil -} - -// getFormattedPolicyFromTemplated returns formatted, policy from a user templated policy -func (p PolicyContainerMap) getFormattedPolicyFromTemplated(policy Policy, flow PolicyFlow, swagger *AdapterInternalAPI) (Policy, error) { - policyFullName := policy.GetFullName() - spec := p[policyFullName].Specification - if err := spec.validatePolicy(policy, flow); err != nil { - swagger.GetID() - loggers.LoggerOasparser.ErrorC(logging.PrintError(logging.Error2204, logging.MINOR, "Operation policy validation failed for API %q in org %q:, policy %q: %v", swagger.GetID(), swagger.OrganizationID, policyFullName, err)) - return policy, err - } - - defRaw := p[policyFullName].Definition.RawData - t, err := template.New("policy-def").Funcs(policyDefFuncMap).Parse(string(defRaw)) - if err != nil { - loggers.LoggerOasparser.ErrorC(logging.PrintError(logging.Error2205, logging.MINOR, "Error parsing the operation policy definition %q into go template of the API %q in org %q: %v", policyFullName, swagger.GetID(), swagger.OrganizationID, err)) - return Policy{}, err - } - - var out bytes.Buffer - err = t.Execute(&out, policy.Parameters) - if err != nil { - loggers.LoggerOasparser.ErrorC(logging.PrintError(logging.Error2206, logging.MINOR, "Error parsing operation policy definition %q of the API %q in org %q: %v", policyFullName, swagger.GetID(), swagger.OrganizationID, err)) - return Policy{}, err - } - - def := PolicyDefinition{} - if err := yaml.Unmarshal(out.Bytes(), &def); err != nil { - loggers.LoggerOasparser.ErrorC(logging.PrintError(logging.Error2207, logging.MINOR, "Error parsing formalized operation policy definition %q into yaml of the API %q in org %q: %v", policyFullName, swagger.GetID(), swagger.OrganizationID, err)) - return Policy{}, err - } - - // Update templated policy itself and return, not updating a pointer to keep the original template values as it is. - policy.Parameters = def.Definition.Parameters - policy.Action = def.Definition.Action - - // Fill default values - spec.fillDefaultsInPolicy(&policy) - - // Check the API Policy supported by APK - // Required params may be comming from default values as defined in the policy specification - // Hence do the validation after filling default values - if err := validatePolicyAction(&policy); err != nil { - loggers.LoggerOasparser.ErrorC(logging.PrintError(logging.Error2208, logging.MINOR, "API policy validation failed, policy: %q of the API %q in org %q: %v", policyFullName, swagger.GetID(), swagger.OrganizationID, err)) - return Policy{}, err - } - return policy, nil -} - -// validatePolicy validates the given policy against the spec -func (spec *PolicySpecification) validatePolicy(policy Policy, flow PolicyFlow) error { - if spec.Data.Name != policy.PolicyName || spec.Data.Version != policy.PolicyVersion { - return fmt.Errorf("invalid policy specification, spec name %q:%q and policy name %q:%q mismatch", - spec.Data.Name, spec.Data.Version, policy.PolicyName, policy.PolicyVersion) - } - if !arrayContains(spec.Data.ApplicableFlows, string(flow)) { - return fmt.Errorf("policy flow %q not supported", flow) - } - - policyPrams, ok := policy.Parameters.(map[string]interface{}) - if ok { - for _, attrib := range spec.Data.PolicyAttributes { - val, found := policyPrams[attrib.Name] - if attrib.Required && !found { - return fmt.Errorf("required paramater %q not found", attrib.Name) - } - - switch v := val.(type) { - case string: - regexStr := attrib.ValidationRegex - if regexStr != "" { - reg, err := regexp.Compile(regexStr) - if err != nil { - return fmt.Errorf("invalid regex expression in policy spec %s, regex: %q", spec.Data.Name, attrib.ValidationRegex) - } - if !reg.MatchString(v) { - return fmt.Errorf("invalid parameter value of attribute %q, regex match failed", attrib.Name) - } - } - } - } - } - - return nil -} - -// fillDefaultsInPolicy updates the policy with default values defined in the spec if the key is not found in the policy -func (spec *PolicySpecification) fillDefaultsInPolicy(policy *Policy) { - if paramMap, isMap := policy.Parameters.(map[string]interface{}); isMap { - for _, attrib := range spec.Data.PolicyAttributes { - if _, ok := paramMap[attrib.Name]; !ok && attrib.DefaultValue != "" { - paramMap[attrib.Name] = attrib.DefaultValue - loggers.LoggerOasparser.Debugf("Update with policy attribute %q of policy %q with default value from spec", - attrib.Name, policy.PolicyName) - } - } - policy.Parameters = paramMap - } -} diff --git a/adapter/internal/oasparser/model/policy_container_test.go b/adapter/internal/oasparser/model/policy_container_test.go deleted file mode 100644 index d0c7bdd1a..000000000 --- a/adapter/internal/oasparser/model/policy_container_test.go +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (c) 2022, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package model - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestPolicySpecificationValidatePolicy(t *testing.T) { - spec := getSampleTestPolicySpec() - - tests := []struct { - policy Policy - flow PolicyFlow - isExpError bool - message string - }{ - { - policy: Policy{ - PolicyName: "fooAddRequestHeader", - PolicyVersion: "v1", - Parameters: map[string]interface{}{"fooName": "user", "fooValue": "admin"}, - }, - flow: policyInFlow, - isExpError: false, - message: "Valid policy should not return error", - }, - { - policy: Policy{ - PolicyName: "fooAddRequestHeader", - PolicyVersion: "v1", - Parameters: map[string]interface{}{"fooName": "$%invalid name%$", "fooValue": "admin"}, - }, - flow: policyInFlow, - isExpError: true, - message: "Invalid value for policy parameter should return error", - }, - { - policy: Policy{ - PolicyName: "fooAddRequestHeader", - PolicyVersion: "v1", - Parameters: map[string]interface{}{"fooName": "user", "fooValue": "admin"}, - }, - flow: policyOutFlow, - isExpError: true, - message: "Invalid policy flow should return error", - }, - { - policy: Policy{ - PolicyName: "invalidName", - PolicyVersion: "v1", - Parameters: map[string]interface{}{"fooName": "user", "fooValue": "admin"}, - }, - flow: policyInFlow, - isExpError: true, - message: "Invalid policy name should return error", - }, - { - policy: Policy{ - PolicyName: "fooAddRequestHeader", - PolicyVersion: "v1", - Parameters: map[string]interface{}{"fooValue": "admin"}, - }, - flow: policyInFlow, - isExpError: true, - message: "Required parameter not found, should return error", - }, - } - - for _, test := range tests { - err := spec.validatePolicy(test.policy, test.flow) - if test.isExpError { - assert.Error(t, err, test.message) - } else { - assert.True(t, err == nil, test.message+", err: %v", err) - } - } -} - -// func TestAPIProjectGetFormattedPolicyFromTemplated(t *testing.T) { -// apiYaml := APIYaml{} -// apiYaml.Data.Operations = []OperationYaml{ -// { -// Target: "/pets", -// Verb: "POST", -// OperationPolicies: OperationPolicies{ -// Request: PolicyList{ -// { -// PolicyName: "fooAddRequestHeader", -// PolicyVersion: "v1", -// Parameters: map[string]interface{}{ -// "fooName": "fooHeaderName", -// "fooValue": "fooHeaderValue", -// }, -// }, -// }, -// }, -// }, -// } - -// spec := getSampleTestPolicySpec() -// specInvalid1 := getSampleTestPolicySpec() -// specInvalid1.Data.Name = "fooAddRequestHeaderInvalid1" -// specInvalid2 := getSampleTestPolicySpec() -// specInvalid2.Data.Name = "fooAddRequestHeaderInvalid2" - -// proj := ProjectAPI{ -// APIYaml: apiYaml, -// Policies: map[string]PolicyContainer{ -// "fooAddRequestHeader_v1": { -// Specification: spec, -// Definition: PolicyDefinition{ -// RawData: getSampleTestPolicyDef(), -// }, -// }, -// "fooAddRequestHeaderInvalid1_v1": { -// Specification: specInvalid1, -// Definition: PolicyDefinition{ -// RawData: getSampleInvalidTestPolicyDef1(), -// }, -// }, -// "fooAddRequestHeaderInvalid2_v1": { -// Specification: specInvalid2, -// Definition: PolicyDefinition{ -// RawData: getSampleInvalidTestPolicyDef2(), -// }, -// }, -// }, -// } - -// expFormattedP := OperationPolicies{ -// Request: PolicyList{ -// { -// PolicyName: "fooAddRequestHeader", -// PolicyVersion: "v1", -// Action: "SET_HEADER", -// IsPassToEnforcer: false, -// Parameters: map[string]interface{}{ -// "headerName": "fooHeaderName", -// "headerValue": "fooHeaderValue", -// }, -// }, -// }, -// } -// actualFormattedP, err := proj.Policies.GetFormattedOperationalPolicies(apiYaml.Data.Operations[0].OperationPolicies, &AdapterInternalAPI{}) -// assert.Nil(t, err) -// assert.Equal(t, expFormattedP, actualFormattedP, "Converting operational policies to format failed") -// } - -func getSampleTestPolicySpec() PolicySpecification { - spec := PolicySpecification{} - spec.Data.Name = "fooAddRequestHeader" - spec.Data.Version = "v1" - spec.Data.ApplicableFlows = []string{"request"} - spec.Data.SupportedGateways = []string{"APK"} - spec.Data.PolicyAttributes = []struct { // redefine struct here, since it is not named, update here if the src changed - Name string `yaml:"name"` - ValidationRegex string `yaml:"validationRegex,omitempty"` - Type string `yaml:"type"` - DefaultValue string `yaml:"defaultValue"` - Required bool `yaml:"required,omitempty"` - }{ - { - Name: "fooName", - ValidationRegex: `^([a-zA-Z_][a-zA-Z\\d_\\-\\ ]*)$`, - Type: "String", - Required: true, - }, - { - Name: "fooValue", - ValidationRegex: `.*`, - Type: "String", - Required: true, - }, - { - Name: "fooNotRequired", - ValidationRegex: `^\S+$`, - Type: "String", - Required: false, - }, - } - return spec -} - -// func getSampleTestPolicyDef() []byte { -// return []byte(` -// definition: -// action: SET_HEADER -// parameters: -// headerName: {{ .fooName }} -// headerValue: {{ .fooValue }} -// `) -// } - -// func getSampleInvalidTestPolicyDef1() []byte { -// return []byte(` -// definition: -// action: SET_HEADER_INVALID_ACTION -// parameters: -// headerName: {{ .fooName }} -// headerValue: {{ .fooValue }} -// `) -// } - -// func getSampleInvalidTestPolicyDef2() []byte { -// return []byte(` -// definition: -// action: SET_HEADER -// parameters: -// headerNameInvalidParam: {{ .fooName }} -// headerValue: {{ .fooValue }} -// `) -// } diff --git a/adapter/internal/oasparser/model/policy_layout.go b/adapter/internal/oasparser/model/policy_layout.go deleted file mode 100644 index 90654b248..000000000 --- a/adapter/internal/oasparser/model/policy_layout.go +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2022, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package model - -import ( - "errors" - "fmt" - - "github.com/wso2/apk/adapter/internal/oasparser/constants" -) - -// supportedPoliciesMap maps (policy action name) -> (policy layout) -var supportedPoliciesMap = map[string]policyLayout{ - constants.ActionHeaderAdd: { - RequiredParams: []string{constants.HeaderName, constants.HeaderValue}, - IsPassToEnforcer: false, - }, - constants.ActionHeaderRemove: { - RequiredParams: []string{constants.HeaderName}, - IsPassToEnforcer: false, - }, - "ADD_QUERY": { - RequiredParams: []string{"queryParamName", "queryParamValue"}, - IsPassToEnforcer: true, - }, - constants.ActionInterceptorService: { - RequiredParams: []string{constants.InterceptorServiceURL, constants.InterceptorServiceIncludes}, - IsPassToEnforcer: false, - }, - constants.ActionRewriteMethod: { - RequiredParams: []string{constants.UpdatedMethod}, - IsPassToEnforcer: true, - }, - constants.ActionRewritePath: { - RequiredParams: []string{constants.RewritePathResourcePath, constants.IncludeQueryParams}, - IsPassToEnforcer: true, - }, - "OPA": { - // Following parameters are not required (optional) - // "rule", token", "additionalProperties", "sendAccessToken", "maxOpenConnections", "maxPerRoute" - // "connectionTimeout", "requestGenerator" - RequiredParams: []string{"serverURL", "policy"}, - IsPassToEnforcer: true, - }, -} - -// PolicyLayout holds the layout of policy that support by APK -type policyLayout struct { - RequiredParams []string - IsPassToEnforcer bool -} - -// validatePolicyAction validates policy against the policy definition that supported by APK -func validatePolicyAction(policy *Policy) error { - if layout, ok := supportedPoliciesMap[policy.Action]; ok { - for _, requiredParam := range layout.RequiredParams { - if params, isMap := policy.Parameters.(map[string]interface{}); isMap { - if _, ok := params[requiredParam]; !ok { - return fmt.Errorf("required parameter %q not found for the policy action %q", requiredParam, policy.Action) - } - } else { - return errors.New("policy params required in map format") - } - } - policy.IsPassToEnforcer = layout.IsPassToEnforcer - } else { - return fmt.Errorf("policy action %q not supported by APK gateway", policy.Action) - } - return nil -}