Skip to content

Commit

Permalink
Merge pull request #2821 from tharindu1st/go-enforcer
Browse files Browse the repository at this point in the history
fix graphql invocation
  • Loading branch information
Krishanx92 authored Feb 16, 2025
2 parents 350537a + 9482c21 commit a5b9fa2
Show file tree
Hide file tree
Showing 12 changed files with 268 additions and 148 deletions.
18 changes: 7 additions & 11 deletions adapter/internal/oasparser/config_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -463,13 +463,7 @@ func GetJWTRequirements(adapterAPI *model.AdapterInternalAPI, jwtIssuers map[str
selectedIssuers = append(selectedIssuers, issuserName)
}
}
if len(selectedIssuers) == 1 {
return &jwt.JwtRequirement{
RequiresType: &jwt.JwtRequirement_ProviderName{
ProviderName: selectedIssuers[0],
},
}
} else if len(selectedIssuers) > 1 {
if len(selectedIssuers) >= 1 {
return &jwt.JwtRequirement{
RequiresType: &jwt.JwtRequirement_RequiresAny{
RequiresAny: &jwt.JwtRequirementOrList{
Expand All @@ -482,11 +476,13 @@ func GetJWTRequirements(adapterAPI *model.AdapterInternalAPI, jwtIssuers map[str
},
})
}
requirements = append(requirements, &jwt.JwtRequirement{
RequiresType: &jwt.JwtRequirement_AllowMissingOrFailed{},
})
return requirements
}(),
},
},
}
}}
}
return nil
}
Expand Down Expand Up @@ -526,8 +522,8 @@ func getjwtAuthFilters(tokenIssuer *v1alpha1.ResolvedJWTIssuer, issuerName strin
jwtProvider := &jwt.JwtProvider{
Issuer: tokenIssuer.Issuer,
Forward: true,
FailedStatusInMetadata: "failed_status",
PayloadInMetadata: "payload_in_metadata",
FailedStatusInMetadata: tokenIssuer.Issuer + "-failed",
PayloadInMetadata: tokenIssuer.Issuer + "-payload",
}
if tokenIssuer.SignatureValidation.JWKS != nil {
logger.LoggerOasparser.Infof("JWKS URL: %s", tokenIssuer.SignatureValidation.JWKS.URL)
Expand Down
16 changes: 8 additions & 8 deletions adapter/internal/oasparser/envoyconf/routes_configs.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const (
DescriptorKeyForPolicy = "policy"
DescriptorKeyForOrganization = "organization"
extAuthzFilterName = "envoy.filters.http.ext_authz"
extProcFilterName = "envoy.filters.http.ext_proc"
extProcFilterName = "envoy.filters.http.ext_proc"

descriptorMetadataKeyForSubscription = "ratelimit:subscription"
descriptorMetadataKeyForUsagePolicy = "ratelimit:usage-policy"
Expand Down Expand Up @@ -77,13 +77,13 @@ const (
DescriptorKeyForAISubscription = "subscription"
)

func generateRouteConfig(routeName string, method *string, match *routev3.RouteMatch, action *routev3.Route_Route, redirectAction *routev3.Route_Redirect,
func generateRouteConfig(apiType string, routeName string, method *string, match *routev3.RouteMatch, action *routev3.Route_Route, redirectAction *routev3.Route_Redirect,
metadata *corev3.Metadata, decorator *routev3.Decorator, typedPerFilterConfig map[string]*anypb.Any,
requestHeadersToAdd []*corev3.HeaderValueOption, requestHeadersToRemove []string,
responseHeadersToAdd []*corev3.HeaderValueOption, responseHeadersToRemove []string, authentication *model.Authentication) *routev3.Route {
cloneTypedPerFilterConfig := cloneTypedPerFilterConfig(typedPerFilterConfig)
//todo: need to fix it in proper way
if authentication == nil || (authentication != nil && (authentication.Disabled || authentication.Oauth2 == nil)) || (method != nil && strings.ToUpper(*method) == "OPTIONS") {
if apiType == constants.REST && (authentication == nil || (authentication != nil && (authentication.Disabled || authentication.Oauth2 == nil)) || (method != nil && strings.ToUpper(*method) == "OPTIONS")) {
logger.LoggerOasparser.Infof("routename%v", routeName)
logger.LoggerOasparser.Infof("authentication is nill %v", authentication == nil)
if authentication != nil {
Expand Down Expand Up @@ -128,7 +128,7 @@ func generateRouteMatch(routeRegex string) *routev3.RouteMatch {
}

func generateRouteAction(apiType string, routeConfig *model.EndpointConfig, ratelimitCriteria *ratelimitCriteria, mirrorClusterNames []string, isBackendBasedAIRatelimitEnabled bool, descriptorValueForBackendBasedAIRatelimit string, weightedCluster *routev3.WeightedCluster_ClusterWeight, isWeighted bool) (action *routev3.Route_Route) {

if isWeighted {
// check if weightedCluster is already in the list
exists := false
Expand All @@ -145,7 +145,7 @@ func generateRouteAction(apiType string, routeConfig *model.EndpointConfig, rate

// if not existing, add to the list
if !exists {
weightedClusters = append(weightedClusters, weightedCluster)
weightedClusters = append(weightedClusters, weightedCluster)
}
action = &routev3.Route_Route{
Route: &routev3.RouteAction{
Expand All @@ -163,7 +163,7 @@ func generateRouteAction(apiType string, routeConfig *model.EndpointConfig, rate
},
},
}
} else {
} else {
action = &routev3.Route_Route{
Route: &routev3.RouteAction{
HostRewriteSpecifier: &routev3.RouteAction_AutoHostRewrite{
Expand All @@ -189,9 +189,9 @@ func generateRouteAction(apiType string, routeConfig *model.EndpointConfig, rate
RetryBackOff: &routev3.RetryPolicy_RetryBackOff{
BaseInterval: durationpb.New(time.Duration(routeConfig.RetryConfig.BaseIntervalInMillis) * time.Millisecond),
},
RetryOn: "retriable-status-codes",
RetryOn: "retriable-status-codes",
RetriableStatusCodes: routeConfig.RetryConfig.StatusCodes,
NumRetries: &wrapperspb.UInt32Value{Value: uint32(routeConfig.RetryConfig.Count)},
NumRetries: &wrapperspb.UInt32Value{Value: uint32(routeConfig.RetryConfig.Count)},
}
action.Route.RetryPolicy = retryPolicy
}
Expand Down
8 changes: 4 additions & 4 deletions adapter/internal/oasparser/envoyconf/routes_with_clusters.go
Original file line number Diff line number Diff line change
Expand Up @@ -1291,7 +1291,7 @@ func createRoutes(params *routeCreateParams) (routes []*routev3.Route, err error
// Create route1 for current method.
// Do not add policies to route config. Send via enforcer
method := operation.GetMethod()
route1 := generateRouteConfig(xWso2Basepath+method, &method, match1, action1, requestRedirectAction, metaData, decorator, perRouteFilterConfigs,
route1 := generateRouteConfig(apiType, xWso2Basepath+method, &method, match1, action1, requestRedirectAction, metaData, decorator, perRouteFilterConfigs,
nil, requestHeadersToRemove, nil, nil, operation.GetAuthentication())

// Create route2 for new method.
Expand All @@ -1302,7 +1302,7 @@ func createRoutes(params *routeCreateParams) (routes []*routev3.Route, err error
action2.Route.RegexRewrite = generateRegexMatchAndSubstitute(routePath, resourcePath, pathMatchType)
}
configToSkipEnforcer := generateFilterConfigToSkipEnforcer()
route2 := generateRouteConfig(xWso2Basepath, &method, match2, action2, requestRedirectAction, metaData, decorator, configToSkipEnforcer,
route2 := generateRouteConfig(apiType, xWso2Basepath, &method, match2, action2, requestRedirectAction, metaData, decorator, configToSkipEnforcer,
requestHeadersToAdd, requestHeadersToRemove, responseHeadersToAdd, responseHeadersToRemove, operation.GetAuthentication())

routes = append(routes, route1)
Expand All @@ -1323,7 +1323,7 @@ func createRoutes(params *routeCreateParams) (routes []*routev3.Route, err error
action.Route.RegexRewrite = generateRegexMatchAndSubstitute(routePath, resourcePath, pathMatchType)
}
method := operation.GetMethod()
route := generateRouteConfig(xWso2Basepath, &method, match, action, requestRedirectAction, metaData, decorator, perRouteFilterConfigs,
route := generateRouteConfig(apiType, xWso2Basepath, &method, match, action, requestRedirectAction, metaData, decorator, perRouteFilterConfigs,
requestHeadersToAdd, requestHeadersToRemove, responseHeadersToAdd, responseHeadersToRemove, operation.GetAuthentication())
routes = append(routes, route)
}
Expand Down Expand Up @@ -1351,7 +1351,7 @@ func createRoutes(params *routeCreateParams) (routes []*routev3.Route, err error
}
// action.Route.RegexRewrite = generateRegexMatchAndSubstitute(rewritePath, newRoutePath, pathMatchType)
}
route := generateRouteConfig(xWso2Basepath, nil, match, action, nil, metaData, decorator, perRouteFilterConfigs,
route := generateRouteConfig(apiType, xWso2Basepath, nil, match, action, nil, metaData, decorator, perRouteFilterConfigs,
nil, requestHeadersToRemove, nil, nil, nil) // general headers to add and remove are included in this methods
routes = append(routes, route)
}
Expand Down
27 changes: 27 additions & 0 deletions gateway/enforcer/internal/authentication/jwt_validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package authentication

import (
"encoding/json"

"github.com/wso2/apk/gateway/enforcer/internal/dto"
"github.com/wso2/apk/gateway/enforcer/internal/requestconfig"
"github.com/wso2/apk/gateway/enforcer/internal/transformer"
)

// ValidateToken validates the JWT token.
func ValidateToken(rch *requestconfig.Holder, jwtTransformer *transformer.JWTTransformer) *dto.ImmediateResponse {
if rch != nil {
if rch.ExternalProcessingEnvoyMetadata.JwtAuthenticationData != nil {
jwtValidationInfo := jwtTransformer.TransformJWTClaims(rch.MatchedAPI.OrganizationID, rch.ExternalProcessingEnvoyMetadata.JwtAuthenticationData)
if jwtValidationInfo != nil {
if jwtValidationInfo.Valid {
rch.JWTValidationInfo = jwtValidationInfo
return nil
}
}
}
}
errorResponse := &dto.ErrorResponse{ErrorMessage: "Invalid Credentials", Code: "900901", ErrorDescription: "Make sure you have provided the correct security credentials"}
jsonData, _ := json.MarshalIndent(errorResponse, "", " ")
return &dto.ImmediateResponse{StatusCode: 401, Message: string(jsonData)}
}
9 changes: 7 additions & 2 deletions gateway/enforcer/internal/authorization/authorization.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,19 @@ package authorization
import (
"fmt"

"github.com/wso2/apk/gateway/enforcer/internal/authentication"
"github.com/wso2/apk/gateway/enforcer/internal/config"
"github.com/wso2/apk/gateway/enforcer/internal/datastore"
"github.com/wso2/apk/gateway/enforcer/internal/dto"
"github.com/wso2/apk/gateway/enforcer/internal/requestconfig"
"github.com/wso2/apk/gateway/enforcer/internal/transformer"
)

// Validate performs the authorization.
func Validate(rch *requestconfig.Holder, subAppDataStore *datastore.SubscriptionApplicationDataStore, cfg *config.Server) *dto.ImmediateResponse {
func Validate(rch *requestconfig.Holder, subAppDataStore *datastore.SubscriptionApplicationDataStore, cfg *config.Server, jwtTransformer *transformer.JWTTransformer) *dto.ImmediateResponse {
if immediateResponse := authentication.ValidateToken(rch, jwtTransformer); immediateResponse != nil {
return immediateResponse
}
if immediateResponse := ValidateScopes(rch, subAppDataStore, cfg); immediateResponse != nil {
return immediateResponse
}
Expand All @@ -36,6 +41,6 @@ func Validate(rch *requestconfig.Holder, subAppDataStore *datastore.Subscription
return immediateResponse
}
cfg.Logger.Info(fmt.Sprintf("Subscription validation successful for the request: %s", rch.MatchedResource.Path))

return nil
}
11 changes: 11 additions & 0 deletions gateway/enforcer/internal/datastore/jwt_issuer_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,14 @@ func (s *JWTIssuerStore) GetJWTIssuerByOrganizationAndIssuer(organization, issue
}
return nil
}

// GetJWTISsuersByOrganization returns the JWTIssuers for the given organization.
// This method is thread-safe.
func (s *JWTIssuerStore) GetJWTISsuersByOrganization(organization string) map[string]*subscription.JWTIssuer {
s.mu.RLock()
defer s.mu.RUnlock()
if orgWiseJWTIssuers, ok := s.jwtIssuers[organization]; ok {
return orgWiseJWTIssuers
}
return nil
}
24 changes: 24 additions & 0 deletions gateway/enforcer/internal/dto/error_response.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2025, 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 dto

// ErrorResponse represents the error response.
type ErrorResponse struct {
ErrorMessage string `json:"error_message"`
Code string `json:"code"`
ErrorDescription string `json:"error_description"`
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,18 @@ type ExternalProcessingEnvoyMetadata struct {

// JwtAuthenticationData represents the JWT authentication data.
type JwtAuthenticationData struct {
Status *Status `json:"status"`
SucessData map[string]*JWTAuthenticationSuccessData `json:"sucessData"`
FailedData map[string]*JWTAuthenticationFailureData `json:"failedData"`
}

// JWTAuthenticationSuccessData represents the success data of the JWT authentication.
type JWTAuthenticationSuccessData struct {
Issuer string `json:"issuer"`
Claims map[string]interface{} `json:"claims"`
}

// Status represents the status of the JWT authentication.
type Status struct {
// JWTAuthenticationFailureData represents the status of the JWT authentication.
type JWTAuthenticationFailureData struct {
Code int `json:"code"`
Message string `json:"message"`
}
34 changes: 28 additions & 6 deletions gateway/enforcer/internal/dto/jwt_validation_info.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,33 @@
/*
* Copyright (c) 2025, 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 dto

// JWTValidationInfo represents the JWT validation info
type JWTValidationInfo struct {
Issuer string `json:"issuer"` // Issuer
ClientID string `json:"clientId"` // Client ID
Subject string `json:"subject"` // Subject
Audiences []string `json:"audiences"` // Audiences
Scopes []string `json:"scopes"` // Scopes
Claims map[string]interface{} `json:"claims"` // Claims
Valid bool `json:"valid"` // Valid
ExpiryTime int64 `json:"expiryTime"` // Expiry time
IssuedTime int64 `json:"issuedTime"` // Issued time
JTI string `json:"jti"` // JTI
ValidationCode int `json:"validationCode"` // Validation code
ValidationMessage string `json:"validationMessage"` // Validation message
Issuer string `json:"issuer"` // Issuer
ClientID string `json:"clientId"` // Client ID
Subject string `json:"subject"` // Subject
Audiences []string `json:"audiences"` // Audiences
Scopes []string `json:"scopes"` // Scopes
Claims map[string]interface{} `json:"claims"` // Claims
}
Loading

0 comments on commit a5b9fa2

Please sign in to comment.