From 64411292049cf0852ade5dc6383a09a716484efb Mon Sep 17 00:00:00 2001 From: Manoj Talreja Date: Wed, 8 Mar 2023 09:56:55 -0800 Subject: [PATCH 1/5] Added new header to capture customattributes --- server/authorization_test.go | 17 +++++----- server/header_context.go | 16 +++++----- server/header_context_test.go | 16 +++++----- server/metadata_context.go | 55 +++++++++++++++++---------------- server/metadata_context_test.go | 31 ++++++++++--------- 5 files changed, 73 insertions(+), 62 deletions(-) diff --git a/server/authorization_test.go b/server/authorization_test.go index 378ae2d0..3a592971 100644 --- a/server/authorization_test.go +++ b/server/authorization_test.go @@ -362,14 +362,15 @@ func TestImmediateAnalytics(t *testing.T) { testAuthMan := &testAuthMan{} ac := &auth.Context{ - ClientID: "client id", - AccessToken: "token", - Application: "app", - APIProducts: []string{"product1"}, - Expires: time.Now(), - DeveloperEmail: "email", - Scopes: []string{"scope"}, - APIKey: "apikey", + ClientID: "client id", + AccessToken: "token", + Application: "app", + APIProducts: []string{"product1"}, + Expires: time.Now(), + DeveloperEmail: "email", + Scopes: []string{"scope"}, + APIKey: "apikey", + CustomAttributes: "", } testAuthMan.sendAuth(ac, auth.ErrBadAuth) diff --git a/server/header_context.go b/server/header_context.go index 158f993f..ed46f8c0 100644 --- a/server/header_context.go +++ b/server/header_context.go @@ -38,6 +38,7 @@ func makeMetadataHeaders(api string, ac *auth.Context, authorized bool) []*core. header(headerEnvironment, ac.Environment()), header(headerOrganization, ac.Organization()), header(headerScope, strings.Join(ac.Scopes, " ")), + header(headerCustomAttributes, ac.CustomAttributes), } if authorized { @@ -77,12 +78,13 @@ func (h *Handler) decodeMetadataHeaders(headers map[string]string) (string, *aut } return api, &auth.Context{ - Context: rootContext, - AccessToken: headers[headerAccessToken], - APIProducts: strings.Split(headers[headerAPIProducts], ","), - Application: headers[headerApplication], - ClientID: headers[headerClientID], - DeveloperEmail: headers[headerDeveloperEmail], - Scopes: strings.Split(headers[headerScope], " "), + Context: rootContext, + AccessToken: headers[headerAccessToken], + APIProducts: strings.Split(headers[headerAPIProducts], ","), + Application: headers[headerApplication], + ClientID: headers[headerClientID], + DeveloperEmail: headers[headerDeveloperEmail], + Scopes: strings.Split(headers[headerScope], " "), + CustomAttributes: headers[headerCustomAttributes], } } diff --git a/server/header_context_test.go b/server/header_context_test.go index e6b1b837..d8c61fa5 100644 --- a/server/header_context_test.go +++ b/server/header_context_test.go @@ -34,13 +34,14 @@ func TestMetadataHeaders(t *testing.T) { "env", } authContext := &auth.Context{ - Context: h, - ClientID: "clientid", - AccessToken: "accesstoken", - Application: "application", - APIProducts: []string{"prod1", "prod2"}, - DeveloperEmail: "dev@google.com", - Scopes: []string{"scope1", "scope2"}, + Context: h, + ClientID: "clientid", + AccessToken: "accesstoken", + Application: "application", + APIProducts: []string{"prod1", "prod2"}, + DeveloperEmail: "dev@google.com", + Scopes: []string{"scope1", "scope2"}, + CustomAttributes: "", } api := "api" opts = makeMetadataHeaders(api, authContext, true) @@ -61,6 +62,7 @@ func TestMetadataHeaders(t *testing.T) { equal(headerApplication, authContext.Application) equal(headerClientID, authContext.ClientID) equal(headerDeveloperEmail, authContext.DeveloperEmail) + equal(headerCustomAttributes, authContext.CustomAttributes) equal(headerEnvironment, authContext.Environment()) equal(headerOrganization, authContext.Organization()) equal(headerScope, strings.Join(authContext.Scopes, " ")) diff --git a/server/metadata_context.go b/server/metadata_context.go index b2bd1ff6..8023d9ba 100644 --- a/server/metadata_context.go +++ b/server/metadata_context.go @@ -26,16 +26,17 @@ import ( const ( extAuthzFilterNamespace = "envoy.filters.http.ext_authz" - headerAuthorized = "x-apigee-authorized" - headerAccessToken = "x-apigee-accesstoken" - headerAPI = "x-apigee-api" - headerAPIProducts = "x-apigee-apiproducts" - headerApplication = "x-apigee-application" - headerClientID = "x-apigee-clientid" - headerDeveloperEmail = "x-apigee-developeremail" - headerEnvironment = "x-apigee-environment" - headerOrganization = "x-apigee-organization" - headerScope = "x-apigee-scope" + headerAuthorized = "x-apigee-authorized" + headerAccessToken = "x-apigee-accesstoken" + headerAPI = "x-apigee-api" + headerAPIProducts = "x-apigee-apiproducts" + headerApplication = "x-apigee-application" + headerClientID = "x-apigee-clientid" + headerDeveloperEmail = "x-apigee-developeremail" + headerEnvironment = "x-apigee-environment" + headerOrganization = "x-apigee-organization" + headerScope = "x-apigee-scope" + headerCustomAttributes = "x-apigee-customattributes" ) // encodeExtAuthzMetadata encodes given api and auth context into @@ -46,15 +47,16 @@ func encodeExtAuthzMetadata(api string, ac *auth.Context, authorized bool) *stru } fields := map[string]*structpb.Value{ - headerAccessToken: stringValueFrom(ac.AccessToken), - headerAPI: stringValueFrom(api), - headerAPIProducts: stringValueFrom(strings.Join(ac.APIProducts, ",")), - headerApplication: stringValueFrom(ac.Application), - headerClientID: stringValueFrom(ac.ClientID), - headerDeveloperEmail: stringValueFrom(ac.DeveloperEmail), - headerEnvironment: stringValueFrom(ac.Environment()), - headerOrganization: stringValueFrom(ac.Organization()), - headerScope: stringValueFrom(strings.Join(ac.Scopes, " ")), + headerAccessToken: stringValueFrom(ac.AccessToken), + headerAPI: stringValueFrom(api), + headerAPIProducts: stringValueFrom(strings.Join(ac.APIProducts, ",")), + headerApplication: stringValueFrom(ac.Application), + headerClientID: stringValueFrom(ac.ClientID), + headerDeveloperEmail: stringValueFrom(ac.DeveloperEmail), + headerEnvironment: stringValueFrom(ac.Environment()), + headerOrganization: stringValueFrom(ac.Organization()), + headerScope: stringValueFrom(strings.Join(ac.Scopes, " ")), + headerCustomAttributes: stringValueFrom(ac.CustomAttributes), } if authorized { fields[headerAuthorized] = stringValueFrom("true") @@ -119,12 +121,13 @@ func (h *Handler) decodeExtAuthzMetadata(fields map[string]*structpb.Value) (str } return api, &auth.Context{ - Context: rootContext, - AccessToken: fields[headerAccessToken].GetStringValue(), - APIProducts: strings.Split(fields[headerAPIProducts].GetStringValue(), ","), - Application: fields[headerApplication].GetStringValue(), - ClientID: fields[headerClientID].GetStringValue(), - DeveloperEmail: fields[headerDeveloperEmail].GetStringValue(), - Scopes: strings.Split(fields[headerScope].GetStringValue(), " "), + Context: rootContext, + AccessToken: fields[headerAccessToken].GetStringValue(), + APIProducts: strings.Split(fields[headerAPIProducts].GetStringValue(), ","), + Application: fields[headerApplication].GetStringValue(), + ClientID: fields[headerClientID].GetStringValue(), + DeveloperEmail: fields[headerDeveloperEmail].GetStringValue(), + Scopes: strings.Split(fields[headerScope].GetStringValue(), " "), + CustomAttributes: fields[headerCustomAttributes].GetStringValue(), } } diff --git a/server/metadata_context_test.go b/server/metadata_context_test.go index 46a150be..315e65b1 100644 --- a/server/metadata_context_test.go +++ b/server/metadata_context_test.go @@ -33,13 +33,14 @@ func TestEncodeMetadata(t *testing.T) { "env", } authContext := &auth.Context{ - Context: h, - ClientID: "clientid", - AccessToken: "accesstoken", - Application: "application", - APIProducts: []string{"prod1", "prod2"}, - DeveloperEmail: "dev@google.com", - Scopes: []string{"scope1", "scope2"}, + Context: h, + ClientID: "clientid", + AccessToken: "accesstoken", + Application: "application", + APIProducts: []string{"prod1", "prod2"}, + DeveloperEmail: "dev@google.com", + Scopes: []string{"scope1", "scope2"}, + CustomAttributes: "{\"tier\":\"standard\"}", } api := "api" metadata := encodeExtAuthzMetadata(api, authContext, true) @@ -63,6 +64,7 @@ func TestEncodeMetadata(t *testing.T) { equal(headerEnvironment, authContext.Environment()) equal(headerOrganization, authContext.Organization()) equal(headerScope, strings.Join(authContext.Scopes, " ")) + equal(headerCustomAttributes, authContext.CustomAttributes) api2, ac2 := h.decodeExtAuthzMetadata(metadata.GetFields()) if api != api2 { @@ -86,13 +88,14 @@ func TestEncodeMetadataAuthorizedField(t *testing.T) { envName: "env", } authContext := &auth.Context{ - Context: h, - ClientID: "clientid", - AccessToken: "accesstoken", - Application: "application", - APIProducts: []string{"prod1", "prod2"}, - DeveloperEmail: "dev@google.com", - Scopes: []string{"scope1", "scope2"}, + Context: h, + ClientID: "clientid", + AccessToken: "accesstoken", + Application: "application", + APIProducts: []string{"prod1", "prod2"}, + DeveloperEmail: "dev@google.com", + Scopes: []string{"scope1", "scope2"}, + CustomAttributes: "", } metadata := encodeExtAuthzMetadata("api", authContext, true) From f698bfd9716a2e2c23e9bda50c67c13dba30ee60 Mon Sep 17 00:00:00 2001 From: Manoj Talreja Date: Wed, 8 Mar 2023 11:19:40 -0800 Subject: [PATCH 2/5] adding values to unit test. --- server/authorization_test.go | 2 +- server/header_context_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/authorization_test.go b/server/authorization_test.go index 3a592971..78b50fc4 100644 --- a/server/authorization_test.go +++ b/server/authorization_test.go @@ -370,7 +370,7 @@ func TestImmediateAnalytics(t *testing.T) { DeveloperEmail: "email", Scopes: []string{"scope"}, APIKey: "apikey", - CustomAttributes: "", + CustomAttributes: "{\"tier\":\"standard\"}", } testAuthMan.sendAuth(ac, auth.ErrBadAuth) diff --git a/server/header_context_test.go b/server/header_context_test.go index d8c61fa5..1bf0b524 100644 --- a/server/header_context_test.go +++ b/server/header_context_test.go @@ -41,7 +41,7 @@ func TestMetadataHeaders(t *testing.T) { APIProducts: []string{"prod1", "prod2"}, DeveloperEmail: "dev@google.com", Scopes: []string{"scope1", "scope2"}, - CustomAttributes: "", + CustomAttributes: "{\"tier\":\"standard\"}", } api := "api" opts = makeMetadataHeaders(api, authContext, true) From a5eefa986901d65dcf2a713a5febca8056b8bf16 Mon Sep 17 00:00:00 2001 From: Manoj Talreja Date: Wed, 8 Mar 2023 17:33:25 -0800 Subject: [PATCH 3/5] update the version of go-lib so it can work. --- go.mod | 4 ++-- go.sum | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 13b32390..6f41aab8 100644 --- a/go.mod +++ b/go.mod @@ -2,10 +2,10 @@ module github.com/apigee/apigee-remote-service-envoy/v2 go 1.16 -// replace github.com/apigee/apigee-remote-service-golib/v2 => ../apigee-remote-service-golib +//replace github.com/apigee/apigee-remote-service-golib/v2 => ../apigee-remote-service-golib require ( - github.com/apigee/apigee-remote-service-golib/v2 v2.0.7-0.20230308165829-ba684bc16fda + github.com/apigee/apigee-remote-service-golib/v2 v2.0.7-0.20230308201312-6db69e217dea github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad github.com/gogo/googleapis v1.4.1 github.com/golang/protobuf v1.5.2 diff --git a/go.sum b/go.sum index 4309977c..4d71cca7 100644 --- a/go.sum +++ b/go.sum @@ -42,8 +42,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/apigee/apigee-remote-service-golib/v2 v2.0.7-0.20230308165829-ba684bc16fda h1:T1VfDgp3mSIXqOiLo14VdwhnwmVjV+/wGESBzr5KOGg= -github.com/apigee/apigee-remote-service-golib/v2 v2.0.7-0.20230308165829-ba684bc16fda/go.mod h1:km/iROUzLa13srZgVP0R31sAcsdgYnCJlvZdCW7ud98= +github.com/apigee/apigee-remote-service-golib/v2 v2.0.7-0.20230308201312-6db69e217dea h1:iwqx15jtWqCTKDjq1hKh3CRjCyl9pI7+ujQijjqXRw0= +github.com/apigee/apigee-remote-service-golib/v2 v2.0.7-0.20230308201312-6db69e217dea/go.mod h1:km/iROUzLa13srZgVP0R31sAcsdgYnCJlvZdCW7ud98= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= From 32abe3a5c3c551d4aff62a0d3e869d2cbd95ac93 Mon Sep 17 00:00:00 2001 From: Manoj Talreja Date: Wed, 8 Mar 2023 17:38:11 -0800 Subject: [PATCH 4/5] add header customattribute only if the value is not empty --- server/metadata_context.go | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/server/metadata_context.go b/server/metadata_context.go index 8023d9ba..af5cf8d9 100644 --- a/server/metadata_context.go +++ b/server/metadata_context.go @@ -47,17 +47,21 @@ func encodeExtAuthzMetadata(api string, ac *auth.Context, authorized bool) *stru } fields := map[string]*structpb.Value{ - headerAccessToken: stringValueFrom(ac.AccessToken), - headerAPI: stringValueFrom(api), - headerAPIProducts: stringValueFrom(strings.Join(ac.APIProducts, ",")), - headerApplication: stringValueFrom(ac.Application), - headerClientID: stringValueFrom(ac.ClientID), - headerDeveloperEmail: stringValueFrom(ac.DeveloperEmail), - headerEnvironment: stringValueFrom(ac.Environment()), - headerOrganization: stringValueFrom(ac.Organization()), - headerScope: stringValueFrom(strings.Join(ac.Scopes, " ")), - headerCustomAttributes: stringValueFrom(ac.CustomAttributes), + headerAccessToken: stringValueFrom(ac.AccessToken), + headerAPI: stringValueFrom(api), + headerAPIProducts: stringValueFrom(strings.Join(ac.APIProducts, ",")), + headerApplication: stringValueFrom(ac.Application), + headerClientID: stringValueFrom(ac.ClientID), + headerDeveloperEmail: stringValueFrom(ac.DeveloperEmail), + headerEnvironment: stringValueFrom(ac.Environment()), + headerOrganization: stringValueFrom(ac.Organization()), + headerScope: stringValueFrom(strings.Join(ac.Scopes, " ")), } + + if ac.CustomAttributes != "" { + fields[headerCustomAttributes] = stringValueFrom(ac.CustomAttributes) + } + if authorized { fields[headerAuthorized] = stringValueFrom("true") } From da202cf275d83f85e828cdaff06eeff8a69c439c Mon Sep 17 00:00:00 2001 From: Manoj Talreja Date: Wed, 8 Mar 2023 20:03:58 -0800 Subject: [PATCH 5/5] updated the unit test also making sure we dont return the CustomAttributes if it is not set in the claims in remoteservice proxy --- server/header_context.go | 5 +++-- server/header_context_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/server/header_context.go b/server/header_context.go index ed46f8c0..d35a3f84 100644 --- a/server/header_context.go +++ b/server/header_context.go @@ -38,9 +38,10 @@ func makeMetadataHeaders(api string, ac *auth.Context, authorized bool) []*core. header(headerEnvironment, ac.Environment()), header(headerOrganization, ac.Organization()), header(headerScope, strings.Join(ac.Scopes, " ")), - header(headerCustomAttributes, ac.CustomAttributes), } - + if ac.CustomAttributes != "" { + headers = append(headers, header(headerCustomAttributes, ac.CustomAttributes)) + } if authorized { headers = append(headers, header(headerAuthorized, "true")) } diff --git a/server/header_context_test.go b/server/header_context_test.go index 1bf0b524..cec04762 100644 --- a/server/header_context_test.go +++ b/server/header_context_test.go @@ -77,6 +77,35 @@ func TestMetadataHeaders(t *testing.T) { } } +func TestCustomAttributeMetadata(t *testing.T) { + h := &multitenantContext{ + &Handler{ + orgName: "org", + envName: "*", + isMultitenant: true, + }, + "env", + } + ac := &auth.Context{ + Context: h, + ClientID: "clientid", + AccessToken: "accesstoken", + Application: "application", + APIProducts: []string{"prod1", "prod2"}, + DeveloperEmail: "dev@google.com", + Scopes: []string{"scope1", "scope2"}, + } + + // Call the function with authorized set to true + headers := makeMetadataHeaders("api", ac, true) + + // Verify that the CustomAttributes header is not included in the headers + for _, h := range headers { + if h.Header.Key == headerCustomAttributes { + t.Errorf("Expected CustomAttributes header to not be included, but found it with value %s", h.Header.Value) + } + } +} func TestMetadataHeadersExceptions(t *testing.T) { opts := makeMetadataHeaders("api", nil, true) if opts != nil {