Search in sources :

Example 1 with ThrottleDataHolder

use of org.apache.synapse.commons.throttle.core.ThrottleDataHolder in project carbon-apimgt by wso2.

the class APIThrottleHandler method doRoleBasedAccessThrottling.

private boolean doRoleBasedAccessThrottling(MessageContext synCtx, ConfigurationContext cc) {
    boolean canAccess = true;
    ThrottleDataHolder dataHolder = (ThrottleDataHolder) cc.getPropertyNonReplicable(ThrottleConstants.THROTTLE_INFO_KEY);
    if (throttle.getThrottleContext(ThrottleConstants.ROLE_BASED_THROTTLE_KEY) == null) {
        // skip role base throttling
        return true;
    }
    ConcurrentAccessController cac = null;
    if (isClusteringEnable) {
        // for clustered  env.,gets it from axis configuration context
        cac = (ConcurrentAccessController) cc.getProperty(key);
    }
    if (!synCtx.isResponse()) {
        // gets the remote caller role name
        AuthenticationContext authContext = APISecurityUtils.getAuthenticationContext(synCtx);
        String accessToken;
        String consumerKey;
        String authorizedUser;
        String roleID;
        String applicationId;
        String applicationTier;
        if (authContext != null) {
            // Although the method says getApiKey, what is actually returned is the Bearer header (accessToken)
            accessToken = authContext.getApiKey();
            consumerKey = authContext.getConsumerKey();
            authorizedUser = authContext.getUsername();
            roleID = authContext.getTier();
            applicationTier = authContext.getApplicationTier();
            applicationId = authContext.getApplicationId();
            if (accessToken == null || roleID == null) {
                log.warn("No consumer key or role information found on the request - " + "Throttling not applied");
                return true;
            }
        } else {
            log.warn("No authentication context information found on the request - " + "Throttling not applied");
            return true;
        }
        // Domain name based throttling
        // check whether a configuration has been defined for this role name or not
        // loads the ThrottleContext
        ThrottleContext resourceContext = throttle.getThrottleContext(RESOURCE_THROTTLE_KEY);
        if (resourceContext == null) {
            log.warn("Unable to load throttle context");
            return true;
        }
        // Loads the ThrottleConfiguration
        ThrottleConfiguration config = resourceContext.getThrottleConfiguration();
        if (config != null) {
            String applicationRoleId = null;
            // If an application level tier has been specified and it is not 'Unlimited'
            if (applicationTier != null && !APIConstants.UNLIMITED_TIER.equals(applicationTier)) {
                // Get the configuration role of the application
                // applicationRoleId = config.getConfigurationKeyOfCaller(applicationTier);
                applicationRoleId = applicationTier;
            }
            AccessInformation info = null;
            // If application level throttling is applied
            if (applicationRoleId != null) {
                ThrottleContext applicationThrottleContext = getApplicationThrottleContext(synCtx, dataHolder, applicationId);
                if (isClusteringEnable) {
                    applicationThrottleContext.setConfigurationContext(cc);
                    applicationThrottleContext.setThrottleId(id);
                }
                // First throttle by application
                try {
                    info = applicationRoleBasedAccessController.canAccess(applicationThrottleContext, applicationId, applicationRoleId);
                    if (log.isDebugEnabled()) {
                        log.debug("Throttle by Application " + applicationId);
                        log.debug("Allowed = " + (info != null ? info.isAccessAllowed() : "false"));
                    }
                } catch (ThrottleException e) {
                    log.warn("Exception occurred while performing role " + "based throttling", e);
                    synCtx.setProperty(APIThrottleConstants.THROTTLED_OUT_REASON, APIThrottleConstants.APPLICATION_LIMIT_EXCEEDED);
                    return false;
                }
                // check for the permission for access
                if (info != null && !info.isAccessAllowed()) {
                    log.info("Exceeded the allocated quota in Application level.");
                    // if the access has denied by rate based throttling
                    if (cac != null) {
                        cac.incrementAndGet();
                        // set back if this is a clustered env
                        if (isClusteringEnable) {
                            cc.setProperty(key, cac);
                            resourceContext.setConfigurationContext(cc);
                            // replicate the current state of ConcurrentAccessController
                            try {
                                Replicator.replicate(cc, new String[] { key });
                            } catch (ClusteringFault clusteringFault) {
                                log.error("Error during replicating states", clusteringFault);
                            }
                        }
                    }
                    synCtx.setProperty(APIThrottleConstants.THROTTLED_OUT_REASON, APIThrottleConstants.APPLICATION_LIMIT_EXCEEDED);
                    return false;
                }
            }
            // ---------------End of application level throttling------------
            // ==============================Start of Resource level throttling======================================
            // get throttling information for given request with resource path and http verb
            // VerbInfoDTO verbInfoDTO = null;
            // verbInfoDTO = validator.getVerbInfoDTOFromAPIData(apiContext, apiVersion, requestPath, httpMethod);
            VerbInfoDTO verbInfoDTO = (VerbInfoDTO) synCtx.getProperty(APIConstants.VERB_INFO_DTO);
            String resourceLevelRoleId = null;
            // no data related to verb information data
            if (verbInfoDTO == null) {
                log.warn("Error while getting throttling information for resource and http verb");
                return false;
            } else {
                // Not only we can proceed
                String resourceAndHTTPVerbThrottlingTier = verbInfoDTO.getThrottling();
                // If there no any tier then we need to set it as unlimited
                if (resourceAndHTTPVerbThrottlingTier == null) {
                    log.warn("Unable to find throttling information for resource and http verb. Throttling will " + "not apply");
                } else {
                    resourceLevelRoleId = resourceAndHTTPVerbThrottlingTier;
                }
                // adding consumerKey and authz_user combination instead of access token to resourceAndHTTPVerbKey
                // This avoids sending more than the permitted number of requests in a unit time by
                // regenerating the access token
                String resourceAndHTTPVerbKey = verbInfoDTO.getRequestKey() + '-' + consumerKey + ':' + authorizedUser;
                // if request not null then only we proceed
                if (resourceLevelRoleId != null) {
                    try {
                        // if application level throttling has passed
                        if (!APIConstants.UNLIMITED_TIER.equals(resourceLevelRoleId) && (info == null || info.isAccessAllowed())) {
                            // If this is a clustered env.
                            if (isClusteringEnable) {
                                resourceContext.setConfigurationContext(cc);
                                resourceContext.setThrottleId(id + "resource");
                            }
                            info = roleBasedAccessController.canAccess(resourceContext, resourceAndHTTPVerbKey, resourceAndHTTPVerbThrottlingTier);
                        }
                    } catch (ThrottleException e) {
                        log.warn("Exception occurred while performing resource" + "based throttling", e);
                        synCtx.setProperty(APIThrottleConstants.THROTTLED_OUT_REASON, APIThrottleConstants.RESOURCE_LIMIT_EXCEEDED);
                        return false;
                    }
                    // check for the permission for access
                    if (info != null && !info.isAccessAllowed()) {
                        log.info("Exceeded the allocated quota in Resource level.");
                        // if the access has denied by rate based throttling
                        if (cac != null) {
                            cac.incrementAndGet();
                            // set back if this is a clustered env
                            if (isClusteringEnable) {
                                cc.setProperty(key, cac);
                                // replicate the current state of ConcurrentAccessController
                                try {
                                    Replicator.replicate(cc, new String[] { key });
                                } catch (ClusteringFault clusteringFault) {
                                    log.error("Error during replicating states", clusteringFault);
                                }
                            }
                        }
                        if (isContinueOnThrottleReached(resourceAndHTTPVerbThrottlingTier)) {
                            // limit has reached.
                            if (synCtx.getProperty(APIConstants.API_USAGE_THROTTLE_OUT_PROPERTY_KEY) == null) {
                                synCtx.setProperty(APIConstants.API_USAGE_THROTTLE_OUT_PROPERTY_KEY, Boolean.TRUE);
                            }
                        } else {
                            synCtx.setProperty(APIThrottleConstants.THROTTLED_OUT_REASON, APIThrottleConstants.RESOURCE_LIMIT_EXCEEDED);
                            return false;
                        }
                    }
                } else {
                    log.warn("Unable to find the throttle policy for role.");
                }
            }
            // ==============================End of Resource level throttling=======================================
            // ---------------Start of API level throttling------------------
            // Domain name based throttling
            // check whether a configuration has been defined for this role name or not
            // loads the ThrottleContext
            ThrottleContext context = throttle.getThrottleContext(ThrottleConstants.ROLE_BASED_THROTTLE_KEY);
            String apiKey;
            if (context == null) {
                log.warn("Unable to load throttle context");
                return true;
            }
            // If this is a clustered env.
            // check for configuration role of the caller
            config = context.getThrottleConfiguration();
            String consumerRoleID = config.getConfigurationKeyOfCaller(roleID);
            if (isClusteringEnable) {
                context.setConfigurationContext(cc);
                context.setThrottleId(id);
            }
            try {
                String apiContext = (String) synCtx.getProperty(RESTConstants.REST_API_CONTEXT);
                String apiVersion = (String) synCtx.getProperty(RESTConstants.SYNAPSE_REST_API_VERSION);
                apiContext = apiContext != null ? apiContext : "";
                apiVersion = apiVersion != null ? apiVersion : "";
                // adding consumerKey and authz_user combination instead of access token to apiKey
                // This avoids sending more than the permitted number of requests in a unit time by
                // regenerating the access token
                apiKey = apiContext + ':' + apiVersion + ':' + consumerKey + ':' + authorizedUser;
                // if application level throttling has passed
                if (!APIConstants.UNLIMITED_TIER.equals(roleID) && (info == null || info.isAccessAllowed())) {
                    // Throttle by access token
                    info = roleBasedAccessController.canAccess(context, apiKey, consumerRoleID);
                }
            } catch (ThrottleException e) {
                log.warn("Exception occurred while performing role " + "based throttling", e);
                synCtx.setProperty(APIThrottleConstants.THROTTLED_OUT_REASON, APIThrottleConstants.API_LIMIT_EXCEEDED);
                return false;
            }
            // check for the permission for access
            if (info != null && !info.isAccessAllowed()) {
                log.info("Exceeded the allocated quota in API level.");
                // if the access has denied by rate based throttling
                if (cac != null) {
                    cac.incrementAndGet();
                    // set back if this is a clustered env
                    if (isClusteringEnable) {
                        cc.setProperty(key, cac);
                        // replicate the current state of ConcurrentAccessController
                        try {
                            Replicator.replicate(cc, new String[] { key });
                        } catch (ClusteringFault clusteringFault) {
                            log.error("Error during replicating states", clusteringFault);
                        }
                    }
                }
                if (isContinueOnThrottleReached(consumerRoleID)) {
                    // limit has reached.
                    if (synCtx.getProperty(APIConstants.API_USAGE_THROTTLE_OUT_PROPERTY_KEY) == null) {
                        synCtx.setProperty(APIConstants.API_USAGE_THROTTLE_OUT_PROPERTY_KEY, Boolean.TRUE);
                    }
                    if (log.isDebugEnabled()) {
                        log.debug("Request throttled at API level for throttle key" + apiKey + ". But role " + consumerRoleID + "allows to continue to serve requests");
                    }
                } else {
                    synCtx.setProperty(APIThrottleConstants.THROTTLED_OUT_REASON, APIThrottleConstants.API_LIMIT_EXCEEDED);
                    return false;
                }
            }
        }
    }
    // ---------------End of API level throttling------------------
    // ---------------Start of Hard throttling------------------
    ThrottleContext hardThrottleContext = throttle.getThrottleContext(APIThrottleConstants.HARD_THROTTLING_CONFIGURATION);
    try {
        String apiContext = (String) synCtx.getProperty(RESTConstants.REST_API_CONTEXT);
        String apiVersion = (String) synCtx.getProperty(RESTConstants.SYNAPSE_REST_API_VERSION);
        apiContext = apiContext != null ? apiContext : "";
        apiVersion = apiVersion != null ? apiVersion : "";
        AuthenticationContext authContext = APISecurityUtils.getAuthenticationContext(synCtx);
        if (hardThrottleContext != null && authContext.getKeyType() != null) {
            String throttleKey = apiContext + ':' + apiVersion + ':' + authContext.getKeyType();
            AccessInformation info = null;
            if (isClusteringEnable) {
                hardThrottleContext.setConfigurationContext(cc);
            }
            if (APIConstants.API_KEY_TYPE_PRODUCTION.equals(authContext.getKeyType())) {
                hardThrottleContext.setThrottleId(id + APIThrottleConstants.PRODUCTION_HARD_LIMIT);
                info = roleBasedAccessController.canAccess(hardThrottleContext, throttleKey, APIThrottleConstants.PRODUCTION_HARD_LIMIT);
            } else if (APIConstants.API_KEY_TYPE_SANDBOX.equals(authContext.getKeyType())) {
                hardThrottleContext.setThrottleId(id + APIThrottleConstants.SANDBOX_HARD_LIMIT);
                info = roleBasedAccessController.canAccess(hardThrottleContext, throttleKey, APIThrottleConstants.SANDBOX_HARD_LIMIT);
            }
            if (log.isDebugEnabled()) {
                log.debug("Throttle by hard limit " + throttleKey);
                log.debug("Allowed = " + (info != null ? info.isAccessAllowed() : "false"));
            }
            if (info != null && !info.isAccessAllowed()) {
                synCtx.setProperty(APIThrottleConstants.THROTTLED_OUT_REASON, APIThrottleConstants.HARD_LIMIT_EXCEEDED);
                log.info("Hard Throttling limit exceeded.");
                return false;
            }
        }
    } catch (ThrottleException e) {
        log.warn("Exception occurred while performing role based throttling", e);
        synCtx.setProperty(APIThrottleConstants.THROTTLED_OUT_REASON, APIThrottleConstants.HARD_LIMIT_EXCEEDED);
        return false;
    }
    return canAccess;
}
Also used : ThrottleContext(org.apache.synapse.commons.throttle.core.ThrottleContext) ThrottleDataHolder(org.apache.synapse.commons.throttle.core.ThrottleDataHolder) AuthenticationContext(org.wso2.carbon.apimgt.gateway.handlers.security.AuthenticationContext) VerbInfoDTO(org.wso2.carbon.apimgt.impl.dto.VerbInfoDTO) AccessInformation(org.apache.synapse.commons.throttle.core.AccessInformation) ThrottleException(org.apache.synapse.commons.throttle.core.ThrottleException) ThrottleConfiguration(org.apache.synapse.commons.throttle.core.ThrottleConfiguration) ConcurrentAccessController(org.apache.synapse.commons.throttle.core.ConcurrentAccessController) ClusteringFault(org.apache.axis2.clustering.ClusteringFault)

Example 2 with ThrottleDataHolder

use of org.apache.synapse.commons.throttle.core.ThrottleDataHolder in project carbon-apimgt by wso2.

the class APIThrottleHandler method doThrottle.

private boolean doThrottle(MessageContext messageContext) {
    boolean isResponse = messageContext.isResponse();
    org.apache.axis2.context.MessageContext axis2MC = ((Axis2MessageContext) messageContext).getAxis2MessageContext();
    ConfigurationContext cc = axis2MC.getConfigurationContext();
    ThrottleDataHolder dataHolder = null;
    if (cc == null) {
        handleException("Error while retrieving ConfigurationContext from messageContext");
    }
    synchronized (cc) {
        dataHolder = (ThrottleDataHolder) cc.getProperty(ThrottleConstants.THROTTLE_INFO_KEY);
        if (dataHolder == null) {
            dataHolder = new ThrottleDataHolder();
            cc.setNonReplicableProperty(ThrottleConstants.THROTTLE_INFO_KEY, dataHolder);
        }
    }
    if ((throttle == null && !isResponse) || (isResponse && concurrentAccessController == null)) {
        isClusteringEnable = isClusteringEnabled();
    }
    if (!isResponse) {
        // if this is a clustered environment
        if (isClusteringEnable) {
            concurrentAccessController = (ConcurrentAccessController) cc.getProperty(key);
        }
        initThrottle(messageContext, cc);
    } else {
        // if the message flow path is OUT , then must lookup from ConfigurationContext -
        // never create ,just get the existing one
        concurrentAccessController = (ConcurrentAccessController) cc.getProperty(key);
    }
    // perform concurrency throttling
    boolean canAccess = doThrottleByConcurrency(isResponse);
    // then do access rate based throttling
    if (canAccess && !isResponse && throttle != null) {
        canAccess = throttleByAccessRate(axis2MC, cc) && doRoleBasedAccessThrottling(messageContext, cc);
    }
    // Just replicate the current state of ConcurrentAccessController
    if (isClusteringEnable && concurrentAccessController != null) {
        try {
            Replicator.replicate(cc);
        } catch (ClusteringFault clusteringFault) {
            handleException("Error during the replicating  states ", clusteringFault);
        }
    }
    if (!canAccess) {
        handleThrottleOut(messageContext);
        return false;
    }
    return true;
}
Also used : ConfigurationContext(org.apache.axis2.context.ConfigurationContext) ThrottleDataHolder(org.apache.synapse.commons.throttle.core.ThrottleDataHolder) Axis2MessageContext(org.apache.synapse.core.axis2.Axis2MessageContext) ClusteringFault(org.apache.axis2.clustering.ClusteringFault)

Example 3 with ThrottleDataHolder

use of org.apache.synapse.commons.throttle.core.ThrottleDataHolder in project wso2-synapse by wso2.

the class ThrottleMediator method init.

public void init(SynapseEnvironment se) {
    if (onAcceptMediator instanceof ManagedLifecycle) {
        ((ManagedLifecycle) onAcceptMediator).init(se);
    } else if (onAcceptSeqKey != null) {
        SequenceMediator onAcceptSeq = (SequenceMediator) se.getSynapseConfiguration().getSequence(onAcceptSeqKey);
        if (onAcceptSeq == null || onAcceptSeq.isDynamic()) {
            se.addUnavailableArtifactRef(onAcceptSeqKey);
        }
    }
    if (onRejectMediator instanceof ManagedLifecycle) {
        ((ManagedLifecycle) onRejectMediator).init(se);
    } else if (onRejectSeqKey != null) {
        SequenceMediator onRejectSeq = (SequenceMediator) se.getSynapseConfiguration().getSequence(onRejectSeqKey);
        if (onRejectSeq == null || onRejectSeq.isDynamic()) {
            se.addUnavailableArtifactRef(onRejectSeqKey);
        }
    }
    // reference to axis2 configuration context
    configContext = ((Axis2SynapseEnvironment) se).getAxis2ConfigurationContext();
    // throttling data holder initialization of
    // runtime throttle data eg :- throttle contexts
    dataHolder = (ThrottleDataHolder) configContext.getProperty(ThrottleConstants.THROTTLE_INFO_KEY);
    if (dataHolder == null) {
        log.debug("Data holder not present in current Configuration Context");
        synchronized (configContext) {
            dataHolder = (ThrottleDataHolder) configContext.getProperty(ThrottleConstants.THROTTLE_INFO_KEY);
            if (dataHolder == null) {
                dataHolder = new ThrottleDataHolder();
                configContext.setNonReplicableProperty(ThrottleConstants.THROTTLE_INFO_KEY, dataHolder);
            }
        }
    }
    // initializes whether clustering is enabled an Env. level
    ClusteringAgent clusteringAgent = configContext.getAxisConfiguration().getClusteringAgent();
    if (clusteringAgent != null) {
        isClusteringEnable = true;
    }
    // static policy initialization
    if (inLinePolicy != null) {
        log.debug("Initializing using static throttling policy : " + inLinePolicy);
        try {
            throttle = ThrottleFactory.createMediatorThrottle(PolicyEngine.getPolicy(inLinePolicy));
            if (throttle != null && concurrentAccessController == null) {
                concurrentAccessController = throttle.getConcurrentAccessController();
                if (concurrentAccessController != null) {
                    dataHolder.setConcurrentAccessController(key, concurrentAccessController);
                }
            }
        } catch (ThrottleException e) {
            handleException("Error processing the throttling policy", e, null);
        }
    }
    // access rate controller initialization
    accessControler = new AccessRateController();
    // replicator for global concurrent state maintenance
    if (isClusteringEnable) {
        concurrentAccessReplicator = new ConcurrentAccessReplicator(configContext);
    }
}
Also used : ThrottleDataHolder(org.apache.synapse.commons.throttle.core.ThrottleDataHolder) ThrottleException(org.apache.synapse.commons.throttle.core.ThrottleException) SequenceMediator(org.apache.synapse.mediators.base.SequenceMediator) AccessRateController(org.apache.synapse.commons.throttle.core.AccessRateController) ClusteringAgent(org.apache.axis2.clustering.ClusteringAgent) ConcurrentAccessReplicator(org.apache.synapse.commons.throttle.core.ConcurrentAccessReplicator)

Aggregations

ThrottleDataHolder (org.apache.synapse.commons.throttle.core.ThrottleDataHolder)3 ClusteringFault (org.apache.axis2.clustering.ClusteringFault)2 ThrottleException (org.apache.synapse.commons.throttle.core.ThrottleException)2 ClusteringAgent (org.apache.axis2.clustering.ClusteringAgent)1 ConfigurationContext (org.apache.axis2.context.ConfigurationContext)1 AccessInformation (org.apache.synapse.commons.throttle.core.AccessInformation)1 AccessRateController (org.apache.synapse.commons.throttle.core.AccessRateController)1 ConcurrentAccessController (org.apache.synapse.commons.throttle.core.ConcurrentAccessController)1 ConcurrentAccessReplicator (org.apache.synapse.commons.throttle.core.ConcurrentAccessReplicator)1 ThrottleConfiguration (org.apache.synapse.commons.throttle.core.ThrottleConfiguration)1 ThrottleContext (org.apache.synapse.commons.throttle.core.ThrottleContext)1 Axis2MessageContext (org.apache.synapse.core.axis2.Axis2MessageContext)1 SequenceMediator (org.apache.synapse.mediators.base.SequenceMediator)1 AuthenticationContext (org.wso2.carbon.apimgt.gateway.handlers.security.AuthenticationContext)1 VerbInfoDTO (org.wso2.carbon.apimgt.impl.dto.VerbInfoDTO)1