Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 65 additions & 10 deletions gateway/enforcer/internal/authorization/subscription.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,28 @@ func ValidateSubscription(rch *requestconfig.Holder, subAppDataStore *datastore.
if rch.AuthenticatedAuthenticationType == authenticator.Oauth2AuthType {
clientID := rch.JWTValidationInfo.ClientID
if clientID != "" {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 1

Suggested change
if clientID != "" {
if clientID != "" {
cfg.Logger.Sugar().Infof("Validating OAuth2 subscription for API: %s v%s", api.Name, api.Version)

appID := getAppIDUsingConsumerKey(clientID, subAppDataStore, api, "OAuth2")
if appID != "" {
appMaps := subAppDataStore.GetApplicationMappings(api.OrganizationID, appID)
appKeyInfo := getAppIDUsingConsumerKey(clientID, subAppDataStore, api, "OAuth2", cfg)
if appKeyInfo != nil {
appMaps := subAppDataStore.GetApplicationMappings(api.OrganizationID, appKeyInfo.AppID)
for _, appMap := range appMaps {
subscriptions := subAppDataStore.GetSubscriptions(api.OrganizationID, appMap.SubscriptionRef)
for _, subscription := range subscriptions {
subscribedAPI := subscription.SubscribedAPI
if subscribedAPI.Name == api.Name {
versionMatched, err := regexp.MatchString(subscribedAPI.Version, api.Version)
if err == nil && versionMatched {
// Check subscription status
cfg.Logger.Sugar().Debugf("Subscription status %+v, Environment: %s", subscription.SubStatus, appKeyInfo.KeyType)
if !isSubscriptionActive(subscription.SubStatus, appKeyInfo.KeyType) {
cfg.Logger.Sugar().Debugf("Subscription is not active. Status: %s, Key Type: %s", subscription.SubStatus, appKeyInfo.KeyType)
return &dto.ImmediateResponse{
StatusCode: 403,
Message: string(forbiddenJSONMessage),
}
}
cfg.Logger.Sugar().Debugf("Subscription validation successful! Status: %s, Key Type: %s", subscription.SubStatus, appKeyInfo.KeyType)
rch.MatchedSubscription = subscription
rch.MatchedApplication = subAppDataStore.GetApplication(api.OrganizationID, appID)
rch.MatchedApplication = subAppDataStore.GetApplication(api.OrganizationID, appKeyInfo.AppID)
return nil
}
}
Expand Down Expand Up @@ -67,6 +77,16 @@ func ValidateSubscription(rch *requestconfig.Holder, subAppDataStore *datastore.
if subscribedAPI.Name == api.Name {
versionMatched, err := regexp.MatchString(subscribedAPI.Version, api.Version)
if err == nil && versionMatched {
// Check subscription status
keyType := "DEFAULT" // Default assumption, might need to be determined differently
cfg.Logger.Sugar().Debugf("Subscription status %+v, Key Type: %s (API Key)", subscription.SubStatus, keyType)
if !isSubscriptionActive(subscription.SubStatus, keyType) {
cfg.Logger.Sugar().Debugf("Subscription is not active. Status: %s", subscription.SubStatus)
return &dto.ImmediateResponse{
StatusCode: 403,
Message: string(forbiddenJSONMessage),
}
}
rch.MatchedSubscription = subscription
rch.MatchedApplication = application
cfg.Logger.Sugar().Debugf("Matched Subscription %+v", rch.MatchedSubscription)
Expand All @@ -87,13 +107,48 @@ func ValidateSubscription(rch *requestconfig.Holder, subAppDataStore *datastore.
return nil
}

func getAppIDUsingConsumerKey(consumerKey string, subAppDatastore *datastore.SubscriptionApplicationDataStore, api *requestconfig.API, securityScheme string) string {
appKeyMapKey := util.PrepareApplicationKeyMappingCacheKey(consumerKey, api.EnvType, securityScheme, api.Environment)
appKeyMap := subAppDatastore.GetApplicationKeyMapping(api.OrganizationID, appKeyMapKey)
if appKeyMap != nil {
return appKeyMap.ApplicationUUID
// Helper function to check if subscription status allows API access
func isSubscriptionActive(subStatus string, keyType string) bool {
switch subStatus {
case "UNBLOCKED":
return true
case "BLOCKED":
return false
case "PROD_ONLY_BLOCKED":
return keyType == "SANDBOX"
default:
return true
}
}

// AppKeyInfo stores the application ID and key type
type AppKeyInfo struct {
AppID string
KeyType string
}

func getAppIDUsingConsumerKey(consumerKey string, subAppDatastore *datastore.SubscriptionApplicationDataStore, api *requestconfig.API, securityScheme string, cfg *config.Server) *AppKeyInfo {
// Try both possible key types since we don't know which one the client is using
keyTypes := []string{"PRODUCTION", "SANDBOX"}

cfg.Logger.Sugar().Debugf("Looking up application for consumerKey=%s, api.EnvType=%s, api.Environment=%s, securityScheme=%s",
consumerKey, api.EnvType, api.Environment, securityScheme)

for _, keyType := range keyTypes {
appKeyMapKey := util.PrepareApplicationKeyMappingCacheKey(consumerKey, keyType, securityScheme, api.Environment)
cfg.Logger.Sugar().Debugf("Trying cache key: %s (keyType=%s)", appKeyMapKey, keyType)
appKeyMap := subAppDatastore.GetApplicationKeyMapping(api.OrganizationID, appKeyMapKey)
if appKeyMap != nil {
cfg.Logger.Sugar().Debugf("Found app mapping: UUID=%s, KeyType=%s", appKeyMap.ApplicationUUID, appKeyMap.KeyType)
return &AppKeyInfo{
AppID: appKeyMap.ApplicationUUID,
KeyType: appKeyMap.KeyType,
}
}
}
return ""
cfg.Logger.Sugar().Warnf("No application mapping found for consumerKey=%s with any key type", consumerKey)
return nil

}
func getApplicationForAPPUUID(api *requestconfig.API, applicationUUID string, subAppDatastore *datastore.SubscriptionApplicationDataStore) *subscription_model.Application {
return subAppDatastore.GetApplication(api.OrganizationID, applicationUUID)
Expand Down
10 changes: 5 additions & 5 deletions gateway/enforcer/internal/datastore/subs_app_datastore.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,15 +166,15 @@ func (ds *SubscriptionApplicationDataStore) GetApplicationMappings(org string, a
}

// GetSubscriptions Get an Subscription by UUID
func (ds *SubscriptionApplicationDataStore) GetSubscriptions(org string, subscriptionID string) map[string]*subscription_model.Subscription {
func (ds *SubscriptionApplicationDataStore) GetSubscriptions(org string, subscriptionID string) []*subscription_model.Subscription {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 3

Suggested change
func (ds *SubscriptionApplicationDataStore) GetSubscriptions(org string, subscriptionID string) []*subscription_model.Subscription {
func (ds *SubscriptionApplicationDataStore) GetSubscriptions(org string, subscriptionID string) []*subscription_model.Subscription {
logger.LoggerSubscriptionDataStore.Debugf("Getting subscription for org: %s, subscriptionID: %s", org, subscriptionID)

ds.mu.RLock()
defer ds.mu.RUnlock()
if _, exists := ds.subscriptions[org]; exists {
if _, exists := ds.subscriptions[org][subscriptionID]; exists {
return ds.subscriptions[org]
if orgSubs, exists := ds.subscriptions[org]; exists {
if subscription, exists := orgSubs[subscriptionID]; exists {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 4

Suggested change
if subscription, exists := orgSubs[subscriptionID]; exists {
if subscription, exists := orgSubs[subscriptionID]; exists {
logger.LoggerSubscriptionDataStore.Debugf("Found subscription with ID: %s for org: %s", subscriptionID, org)

return []*subscription_model.Subscription{subscription}
}
}
return nil
return []*subscription_model.Subscription{}
}

// GetSubscription Get an Subscription by UUID
Expand Down
Loading