Skip to content

Commit

Permalink
Merge pull request #1170 from sgayangi/sgayangi-header-modifier
Browse files Browse the repository at this point in the history
[APK] Add implementation for HTTPRoute filters
  • Loading branch information
sgayangi authored Jul 1, 2024
2 parents 12813c2 + cae6e2a commit ed69588
Show file tree
Hide file tree
Showing 5 changed files with 449 additions and 60 deletions.
168 changes: 155 additions & 13 deletions apim-apk-agent/pkg/managementserver/rest_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
"github.com/gin-gonic/gin"
"github.com/wso2/product-apim-tooling/apim-apk-agent/config"
logger "github.com/wso2/product-apim-tooling/apim-apk-agent/pkg/loggers"

"github.com/wso2/product-apim-tooling/apim-apk-agent/pkg/utils"
"gopkg.in/yaml.v2"
)
Expand Down Expand Up @@ -312,20 +311,58 @@ func createDeployementYaml(vhost string) string {

// APIOperation represents the desired struct format for each API operation
type APIOperation struct {
ID string `yaml:"id"`
Target string `yaml:"target"`
Verb string `yaml:"verb"`
AuthType string `yaml:"authType"`
ThrottlingPolicy string `yaml:"throttlingPolicy"`
Scopes []string `yaml:"scopes"`
UsedProductIDs []string `yaml:"usedProductIds"`
OperationPolicies struct {
Request []string `yaml:"request"`
Response []string `yaml:"response"`
Fault []string `yaml:"fault"`
} `yaml:"operationPolicies"`
ID string `yaml:"id"`
Target string `yaml:"target"`
Verb string `yaml:"verb"`
AuthType string `yaml:"authType"`
ThrottlingPolicy string `yaml:"throttlingPolicy"`
Scopes []string `yaml:"scopes"`
UsedProductIDs []string `yaml:"usedProductIds"`
OperationPolicies OperationPolicies `yaml:"operationPolicies"`
}

// OperationPolicies contains the request, response and fault policies for an operation
type OperationPolicies struct {
Request []OperationPolicy `yaml:"request"`
Response []OperationPolicy `yaml:"response"`
Fault []string `yaml:"fault"`
}

// OperationPolicy represents the desired struct format for an Operation Policy
type OperationPolicy struct {
PolicyName string `yaml:"policyName"`
PolicyVersion string `yaml:"policyVersion"`
PolicyID string `yaml:"policyId,omitempty"`
Parameters FilterParameters `yaml:"parameters"`
}

// FilterParameters interface is used to define the type of parameters that can be used in an operation policy.
type FilterParameters interface {
isFilterParameters()
}

func (h Header) isFilterParameters() {}

// Header contains the request and response header modifier information
type Header struct {
Name string `json:"headerName" yaml:"headerName"`
Value string `json:"headerValue,omitempty" yaml:"headerValue,omitempty"`
}

// RedirectRequest contains the url to send the redirected request
type RedirectRequest struct {
URL string `json:"url"`
}

func (r RedirectRequest) isFilterParameters() {}

// MirrorRequest contains the url to mirror the request to
type MirrorRequest struct {
URL string `json:"url"`
}

func (m MirrorRequest) isFilterParameters() {}

// OpenAPIPaths represents the structure of the OpenAPI specification YAML file
type OpenAPIPaths struct {
Paths map[string]map[string]interface{} `yaml:"paths"`
Expand Down Expand Up @@ -364,6 +401,8 @@ type Scope struct {

func extractOperations(event APICPEvent) ([]APIOperation, []ScopeWrapper, error) {
var apiOperations []APIOperation
var requestOperationPolicies []OperationPolicy
var responseOperationPolicies []OperationPolicy
scopewrappers := map[string]ScopeWrapper{}
if strings.ToUpper(event.API.APIType) == "GRAPHQL" {
for _, operation := range event.API.Operations {
Expand Down Expand Up @@ -401,12 +440,115 @@ func extractOperations(event APICPEvent) ([]APIOperation, []ScopeWrapper, error)
Shared: false,
}
}
// Process filters
for _, operationLevelFilter := range operationFromDP.Filters {
switch filter := operationLevelFilter.(type) {
// Header modification policies
case *APKHeaders:
requestHeaders := filter.RequestHeaders
// Add headers
if requestHeaders.AddHeaders != nil && len(requestHeaders.AddHeaders) > 0 {
logger.LoggerMgtServer.Debugf("Processing request filter for header addition")
for _, requestHeader := range requestHeaders.AddHeaders {
operationPolicy := OperationPolicy{
PolicyName: "ccAddHeader",
PolicyVersion: "v2",
Parameters: Header{
Name: requestHeader.Name,
Value: requestHeader.Value,
},
}
requestOperationPolicies = append(requestOperationPolicies, operationPolicy)
}
}

// Remove headers
if requestHeaders.RemoveHeaders != nil && len(requestHeaders.RemoveHeaders) > 0 {
logger.LoggerMgtServer.Debugf("Processing request filter for header removal")
for _, requestHeader := range requestHeaders.RemoveHeaders {
operationPolicy := OperationPolicy{
PolicyName: "ccRemoveHeader",
PolicyVersion: "v2",
Parameters: Header{
Name: requestHeader,
},
}
requestOperationPolicies = append(responseOperationPolicies, operationPolicy)
}
}

responseHeaders := filter.ResponseHeaders
// Add headers
if responseHeaders.AddHeaders != nil && len(responseHeaders.AddHeaders) > 0 {
logger.LoggerMgtServer.Debugf("Processing response filter for header addition")
for _, responseHeader := range responseHeaders.AddHeaders {
operationPolicy := OperationPolicy{
PolicyName: "ccAddHeader",
PolicyVersion: "v2",
Parameters: Header{
Name: responseHeader.Name,
Value: responseHeader.Value,
},
}
responseOperationPolicies = append(responseOperationPolicies, operationPolicy)
}
}

// Remove headers
if responseHeaders.RemoveHeaders != nil && len(responseHeaders.RemoveHeaders) > 0 {
logger.LoggerMgtServer.Debugf("Processing response filter for header removal")
for _, responseHeader := range responseHeaders.RemoveHeaders {
operationPolicy := OperationPolicy{
PolicyName: "ccRemoveHeader",
PolicyVersion: "v2",
Parameters: Header{
Name: responseHeader,
},
}
responseOperationPolicies = append(responseOperationPolicies, operationPolicy)
}
}
// Mirror request
case *APKMirrorRequest:
logger.LoggerMgtServer.Debugf("Processing request filter for request mirroring")
for _, url := range filter.URLs {
operationPolicy := OperationPolicy{
PolicyName: "ccMirrorRequest",
PolicyVersion: "v1",
Parameters: MirrorRequest{
URL: url,
},
}
requestOperationPolicies = append(requestOperationPolicies, operationPolicy)
}

// Redirect request
case *APKRedirectRequest:
logger.LoggerMgtServer.Debugf("Processing request filter for request redirection")
operationPolicy := OperationPolicy{
PolicyName: "ccRedirectRequest",
PolicyVersion: "v1",
Parameters: MirrorRequest{
URL: filter.URL,
},
}
requestOperationPolicies = append(requestOperationPolicies, operationPolicy)

default:
logger.LoggerMgtServer.Errorf("Unknown filter type ")
}
}

apiOp := APIOperation{
Target: path,
Verb: verb,
AuthType: "Application & Application User",
ThrottlingPolicy: "Unlimited",
Scopes: scopes,
OperationPolicies: OperationPolicies{
Request: requestOperationPolicies,
Response: responseOperationPolicies,
},
}
apiOperations = append(apiOperations, apiOp)
}
Expand Down
67 changes: 64 additions & 3 deletions apim-apk-agent/pkg/managementserver/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,74 @@ type API struct {
Operations []OperationFromDP `json:"operations"`
}

// APKHeaders contains the request and response header modifier information
type APKHeaders struct {
Policy
RequestHeaders APKHeaderModifier `json:"requestHeaders"`
ResponseHeaders APKHeaderModifier `json:"responseHeaders"`
}

// APKHeaderModifier contains header modifier values
type APKHeaderModifier struct {
AddHeaders []APKHeader `json:"addHeaders"`
RemoveHeaders []string `json:"removeHeaders"`
}

// APKHeader contains the header information
type APKHeader struct {
Name string `json:"headerName" yaml:"headerName"`
Value string `json:"headerValue,omitempty" yaml:"headerValue,omitempty"`
}

// OperationFromDP holds the path, verb, throttling and interceptor policy
type OperationFromDP struct {
Path string `json:"path"`
Verb string `json:"verb"`
Scopes []string `json:"scopes"`
Path string `json:"path"`
Verb string `json:"verb"`
Scopes []string `json:"scopes"`
Filters []Filter `json:"filters"`
}

// Policy holds the policy name and version
type Policy struct {
PolicyName string `json:"policyName"`
PolicyVersion string `json:"policyVersion"`
}

// Filter interface is used to define the type of parameters that can be used in an operation policy
type Filter interface {
GetPolicyName() string
GetPolicyVersion() string
isFilter()
}

// GetPolicyName returns the name of the policy sent to the APIM
func (p *Policy) GetPolicyName() string {
return p.PolicyName
}

// GetPolicyVersion returns the version of the policy sent to the APIM
func (p *Policy) GetPolicyVersion() string {
return p.PolicyVersion
}

func (h APKHeaders) isFilter() {}

// APKRedirectRequest defines the parameters of a redirect request policy sent from the APK
type APKRedirectRequest struct {
Policy
URL string `json:"url"`
}

func (r APKRedirectRequest) isFilter() {}

// APKMirrorRequest defines the parameters of a mirror request policy sent from the APK
type APKMirrorRequest struct {
Policy
URLs []string `json:"urls"`
}

func (m APKMirrorRequest) isFilter() {}

// CORSPolicy hold cors configs
type CORSPolicy struct {
AccessControlAllowCredentials bool `json:"accessControlAllowCredentials,omitempty"`
Expand Down
35 changes: 34 additions & 1 deletion apim-apk-agent/pkg/transformer/api_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,41 @@ type Parameter interface {
isParameter()
}

// URLList contains the urls for mirror and redirect request policies
type URLList struct {
URL string `json:"url,omitempty" yaml:"url,omitempty"`
URLs []string `json:"urls,omitempty" yaml:"urls,omitempty"`
}

func (u URLList) isParameter() {}

// HeaderList contains the list of headers for header modification
type HeaderList struct {
Headers []Header
Names []string
}

// MarshalYAML for both []Header and []string
func (h HeaderList) MarshalYAML() (interface{}, error) {
if len(h.Headers) > 0 {
return map[string]interface{}{"headers": h.Headers}, nil
}
if len(h.Names) > 0 {
return map[string]interface{}{"headers": h.Names}, nil
}
return nil, nil
}

// Header contains the information for header modification
type Header struct {
HeaderName string `yaml:"name"`
HeaderValue string `yaml:"value,omitempty"`
}

func (h HeaderList) isParameter() {}

// InterceptorService holds configuration details for configuring interceptor
// for a aperticular API requests or responses.
// for particular API requests or responses.
type InterceptorService struct {
BackendURL string `yaml:"backendUrl,omitempty"`
HeadersEnabled bool `yaml:"headersEnabled,omitempty"`
Expand Down
47 changes: 47 additions & 0 deletions apim-apk-agent/pkg/transformer/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,51 @@ const (
// Optionality constants
mandatory = "mandatory"
optional = "optional"

// APIM Mediation constants
interceptorService = "ccCallInterceptorService"
backendJWT = "BackEndJWT"
addHeader = "ccAddHeader"
removeHeader = "ccRemoveHeader"
mirrorRequest = "ccMirrorRequest"
redirectRequest = "ccRedirectRequest"

// Interceptor constants
requestHeader = "request_header"
requestBody = "request_body"
requestTrailers = "request_trailers"
requestContext = "request_context"
includes = "includes"
interceptorServiceURL = "interceptorServiceURL"
https = "https"
requestInterceptorSecretName = "request-interceptor-tls-secret"
responseInterceptorSecretName = "response-interceptor-tls-secret"
tlsKey = "tls.crt"

// BackendJWT constants
encoding = "encoding"
header = "header"
signingAlgorithm = "signingAlgorithm"
tokenTTL = "tokenTTL"
base64Url = "Base64Url"

// APK Operation Policy constants
interceptorPolicy = "Interceptor"
backendJWTPolicy = "BackendJwt"
addHeaderPolicy = "AddHeaders"
removeHeaderPolicy = "RemoveHeaders"
requestRedirectPolicy = "RequestRedirect"
requestMirrorPolicy = "RequestMirror"

// APK BackendJWT parameter constants
base64url = "Base64url"

// APK header modification parameter constants
url = "url"
headerName = "headerName"
headerValue = "headerValue"

// Version constants
v1 = "v1"
v2 = "v2"
)
Loading

0 comments on commit ed69588

Please sign in to comment.