Skip to content

Commit

Permalink
Add support for redirect and mirror filters
Browse files Browse the repository at this point in the history
  • Loading branch information
sgayangi committed Jul 1, 2024
1 parent 5658289 commit cae6e2a
Show file tree
Hide file tree
Showing 5 changed files with 220 additions and 59 deletions.
157 changes: 117 additions & 40 deletions apim-apk-agent/pkg/managementserver/rest_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,12 +330,39 @@ type OperationPolicies struct {

// 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 Header `yaml:"parameters"`
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 @@ -413,52 +440,102 @@ 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)
}
}

// Request headers
requestHeaders := operationFromDP.Headers.RequestHeaders
if len(requestHeaders.AddHeaders) > 0 {
for _, requestHeader := range requestHeaders.AddHeaders {
operationPolicy := OperationPolicy{
PolicyName: "addHeader",
PolicyVersion: "v2",
Parameters: requestHeader,
// 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)
}
}
requestOperationPolicies = append(requestOperationPolicies, operationPolicy)
}
}

if len(requestHeaders.RemoveHeaders) > 0 {
for _, requestHeader := range requestHeaders.RemoveHeaders {
operationPolicy := OperationPolicy{
PolicyName: "removeHeader",
PolicyVersion: "v1",
Parameters: Header{Name: requestHeader},
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)
}
}
requestOperationPolicies = append(requestOperationPolicies, operationPolicy)
}
}

// Response headers
responseHeaders := operationFromDP.Headers.ResponseHeaders
if len(responseHeaders.AddHeaders) > 0 {
for _, responseHeader := range responseHeaders.AddHeaders {
operationPolicy := OperationPolicy{
PolicyName: "addHeader",
PolicyVersion: "v2",
Parameters: responseHeader,
// 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)
}
responseOperationPolicies = append(responseOperationPolicies, operationPolicy)
}
}

if responseHeaders.RemoveHeaders != nil && len(responseHeaders.RemoveHeaders) > 0 {
for _, responseHeader := range responseHeaders.RemoveHeaders {
// Redirect request
case *APKRedirectRequest:
logger.LoggerMgtServer.Debugf("Processing request filter for request redirection")
operationPolicy := OperationPolicy{
PolicyName: "removeHeader",
PolicyName: "ccRedirectRequest",
PolicyVersion: "v1",
Parameters: Header{Name: responseHeader},
Parameters: MirrorRequest{
URL: filter.URL,
},
}
responseOperationPolicies = append(responseOperationPolicies, operationPolicy)
requestOperationPolicies = append(requestOperationPolicies, operationPolicy)

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

Expand Down
64 changes: 53 additions & 11 deletions apim-apk-agent/pkg/managementserver/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,20 +146,21 @@ type API struct {
Operations []OperationFromDP `json:"operations"`
}

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

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

// Header contains the header information
type Header struct {
// APKHeader contains the header information
type APKHeader struct {
Name string `json:"headerName" yaml:"headerName"`
Value string `json:"headerValue,omitempty" yaml:"headerValue,omitempty"`
}
Expand All @@ -169,9 +170,50 @@ type OperationFromDP struct {
Path string `json:"path"`
Verb string `json:"verb"`
Scopes []string `json:"scopes"`
Headers Headers `json:"headers"`
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
8 changes: 8 additions & 0 deletions apim-apk-agent/pkg/transformer/api_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ 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
Expand Down
17 changes: 11 additions & 6 deletions apim-apk-agent/pkg/transformer/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,10 @@ const (
// APIM Mediation constants
interceptorService = "ccCallInterceptorService"
backendJWT = "BackEndJWT"
addHeader = "addHeader"
removeHeader = "removeHeader"
addHeader = "ccAddHeader"
removeHeader = "ccRemoveHeader"
mirrorRequest = "ccMirrorRequest"
redirectRequest = "ccRedirectRequest"

// Interceptor constants
requestHeader = "request_header"
Expand All @@ -91,15 +93,18 @@ const (
base64Url = "Base64Url"

// APK Operation Policy constants
interceptorPolicy = "Interceptor"
backendJWTPolicy = "BackendJwt"
addHeaderPolicy = "AddHeaders"
removeHeaderPolicy = "RemoveHeaders"
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"

Expand Down
33 changes: 31 additions & 2 deletions apim-apk-agent/pkg/transformer/transformer.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,9 +225,9 @@ func getReqAndResInterceptors(reqPolicyCount, resPolicyCount int, reqPolicies []
var requestPolicyList, responsePolicyList []OperationPolicy
var interceptorParams *InterceptorService
var requestInterceptorPolicy, responseInterceptorPolicy, requestBackendJWTPolicy OperationPolicy
var requestAddHeader, requestRemoveHeader, responseAddHeader, responseRemoveHeader OperationPolicy
var requestAddHeader, requestRemoveHeader, responseAddHeader, responseRemoveHeader, mirrorRequestPolicy OperationPolicy
var requestAddHeaderList, responseAddHeaderList []Header
var requestRemoveHeaderList, responseRemoveHeaderList []string
var requestRemoveHeaderList, responseRemoveHeaderList, mirrorUrls []string

if reqPolicyCount > 0 {
for _, reqPolicy := range reqPolicies {
Expand Down Expand Up @@ -333,6 +333,29 @@ func getReqAndResInterceptors(reqPolicyCount, resPolicyCount int, reqPolicies []
}
headerName := reqPolicy.Parameters[headerName].(string)
requestRemoveHeaderList = append(requestRemoveHeaderList, headerName)
} else if reqPolicy.PolicyName == redirectRequest {
logger.LoggerTransformer.Debugf("RedirectRequest Type Request Policy: %v", reqPolicy)
redirectRequestPolicy := OperationPolicy{
PolicyName: requestRedirectPolicy,
PolicyVersion: v1,
Parameters: URLList{
URL: reqPolicy.Parameters[url].(string),
},
}
requestPolicyList = append(requestPolicyList, redirectRequestPolicy)
} else if reqPolicy.PolicyName == mirrorRequest {
logger.LoggerTransformer.Debugf("MirrorRequest Type Request Policy: %v", reqPolicy)
if mirrorRequestPolicy.PolicyName == "" {
mirrorRequestPolicy = OperationPolicy{
PolicyName: requestMirrorPolicy,
PolicyVersion: v1,
}
mirrorUrls = []string{}
}
if reqPolicyParameters, ok := reqPolicy.Parameters[url]; ok {
url := reqPolicyParameters.(string)
mirrorUrls = append(mirrorUrls, url)
}
}
}
}
Expand Down Expand Up @@ -437,6 +460,12 @@ func getReqAndResInterceptors(reqPolicyCount, resPolicyCount int, reqPolicies []
}
requestPolicyList = append(requestPolicyList, requestRemoveHeader)
}
if mirrorRequestPolicy.PolicyName != "" {
mirrorRequestPolicy.Parameters = URLList{
URLs: mirrorUrls,
}
requestPolicyList = append(requestPolicyList, mirrorRequestPolicy)
}
}

if resPolicyCount > 0 {
Expand Down

0 comments on commit cae6e2a

Please sign in to comment.