/**
  * Init the access for a particular caller , caller will registered with context
  *
  * @param configuration -The Configuration for this caller
  * @param throttleContext -The Throttle Context
  * @param currentTime -The system current time in milliseconds
  */
 private void initAccess(
     CallerConfiguration configuration, ThrottleContext throttleContext, long currentTime) {
   // This block should be synchronize by key as multiple threads can access this.
   this.unitTime = configuration.getUnitTime();
   this.firstAccessTime = currentTime;
   this.nextTimeWindow = this.firstAccessTime + this.unitTime;
   // Also we need to pick counter value associated with time window.
   throttleContext.addCallerContext(this, this.id);
   throttleContext.replicateTimeWindow(this.id);
 }
  /**
   * Clean up the callers - remove all callers that have expired their time window
   *
   * @param configuration
   * @param throttleContext
   * @param currentTime
   */
  public void cleanUpCallers(
      CallerConfiguration configuration, ThrottleContext throttleContext, long currentTime) {

    if (log.isDebugEnabled()) {
      log.debug("Cleaning up the inactive caller's states ... ");
    }
    if (configuration == null) {
      if (log.isDebugEnabled()) {
        log.debug("Couldn't find the configuration .");
      }
      return;
    }
    // if number of access for a unit time is less than MAX and
    // if the unit time period (session time) has over

    int maxRequest = configuration.getMaximumRequestPerUnitTime();
    if (!(maxRequest == 0)) {
      if ((this.globalCount.get() + this.localCount.get()) <= (maxRequest - 1)) {
        if (this.nextTimeWindow != 0 && this.nextTimeWindow < (currentTime - this.unitTime)) {
          if (log.isDebugEnabled()) {
            log.debug("Removing caller with id " + this.id);
          }
          // Removes the previous callercontext and Sends the current state to
          //  others (clustered env)
          throttleContext.removeAndDestroyShareParamsOfCaller(id);
        }
      } else {
        // if number of access for a unit time has just been greater than MAX
        // now same as a new session
        // OR
        //  if caller in prohibit session  and prohibit period has just over and only
        if ((this.nextAccessTime == 0) || this.nextAccessTime < (currentTime - this.unitTime)) {
          if (this.nextTimeWindow != 0 && this.nextTimeWindow < (currentTime - this.unitTime)) {
            if (log.isDebugEnabled()) {
              log.debug("Removing caller with id " + this.id);
            }
            // Removes the previous callercontext and Sends
            //  the current state to others (clustered env)
            throttleContext.removeAndDestroyShareParamsOfCaller(id);
          }
        }
      }
    }
  }
Example #3
0
  /**
   * Helper method for handling role based Access throttling
   *
   * @param messageContext MessageContext - message level states
   * @return true if access is allowed through concurrent throttling ,o.w false
   */
  private boolean doRoleBasedAccessThrottling(
      Throttle throttle, MessageContext messageContext, boolean isClusteringEnable)
      throws AxisFault, ThrottleException {

    boolean canAccess = true;
    ConfigurationContext cc = messageContext.getConfigurationContext();
    String throttleId = throttle.getId();

    String key = null;
    ConcurrentAccessController cac = null;
    if (isClusteringEnable) {
      // for clustered  env.,gets it from axis configuration context
      key = ThrottleConstants.THROTTLE_PROPERTY_PREFIX + throttleId + ThrottleConstants.CAC_SUFFIX;
      cac = (ConcurrentAccessController) cc.getProperty(key);
    }

    if (messageContext.getFLOW() == MessageContext.IN_FLOW) {
      // gets the remote caller role name
      String consumerKey = null;
      boolean isAuthenticated = false;
      String roleID = null;
      HttpServletRequest request =
          (HttpServletRequest)
              messageContext.getPropertyNonReplicable(HTTPConstants.MC_HTTP_SERVLETREQUEST);
      if (request != null) {
        String oAuthHeader = request.getHeader("OAuth");
        //                consumerKey = Utils.extractCustomerKeyFromAuthHeader(oAuthHeader);
        //                roleID = Utils.extractCustomerKeyFromAuthHeader(oAuthHeader);
        DummyAuthenticator authFuture = new DummyAuthenticator(oAuthHeader);
        consumerKey = authFuture.getAPIKey();
        new DummyHandler().authenticateUser(authFuture);
        roleID = (String) authFuture.getAuthorizedRoles().get(0);
        isAuthenticated = authFuture.isAuthenticated();
      }

      if (!isAuthenticated) {
        throw new AxisFault(
            " Access deny for a "
                + "caller with consumer Key: "
                + consumerKey
                + " "
                + " : Reason : Authentication failure");
      }
      // Domain name based throttling
      // check whether a configuration has been defined for this role name or not
      String consumerRoleID = null;
      if (consumerKey != null && isAuthenticated) {
        // loads the ThrottleContext
        ThrottleContext context =
            throttle.getThrottleContext(ThrottleConstants.ROLE_BASED_THROTTLE_KEY);
        if (context != null) {
          // Loads the ThrottleConfiguration
          ThrottleConfiguration config = context.getThrottleConfiguration();
          if (config != null) {
            // check for configuration for this caller
            consumerRoleID = config.getConfigurationKeyOfCaller(roleID);
            if (consumerRoleID != null) {
              // If this is a clustered env.
              if (isClusteringEnable) {
                context.setConfigurationContext(cc);
                context.setThrottleId(throttleId);
              }
              AccessInformation infor =
                  roleBasedAccessController.canAccess(context, consumerKey, consumerRoleID);
              StatCollector.collect(infor, consumerKey, ThrottleConstants.ROLE_BASE);
              // check for the permission for access
              if (!infor.isAccessAllowed()) {

                // In the case of both of concurrency throttling and
                // rate based throttling have enabled ,
                // if the access rate less than maximum concurrent access ,
                // then it is possible to occur death situation.To avoid that reset,
                // 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 {
                      if (debugOn) {
                        log.debug(
                            "Going to replicates the "
                                + "states of the ConcurrentAccessController"
                                + " with key : "
                                + key);
                      }
                      Replicator.replicate(cc, new String[] {key});
                    } catch (ClusteringFault clusteringFault) {
                      log.error("Error during replicating states ", clusteringFault);
                    }
                  }
                }
                throw new AxisFault(
                    " Access deny for a "
                        + "caller with Domain "
                        + consumerKey
                        + " "
                        + " : Reason : "
                        + infor.getFaultReason());
              }
            } else {
              if (debugOn) {
                log.debug(
                    "Could not find the Throttle Context for role-Based "
                        + "Throttling for role name "
                        + consumerKey
                        + " Throttling for this "
                        + "role name may not be configured from policy");
              }
            }
          }
        }
      } else {
        if (debugOn) {
          log.debug("Could not find the role of the caller - role based throttling NOT applied");
        }
      }
    }
    return canAccess;
  }
Example #4
0
  /**
   * processing through the throttle 1) concurrent throttling 2) access rate based throttling -
   * domain or ip
   *
   * @param throttle The Throttle object - holds all configuration and state data of the throttle
   * @param messageContext The MessageContext , that holds all data per message basis
   * @throws AxisFault Throws when access must deny for caller
   * @throws ThrottleException ThrottleException
   */
  public void process(Throttle throttle, MessageContext messageContext)
      throws ThrottleException, AxisFault {

    String throttleId = throttle.getId();
    ConfigurationContext cc = messageContext.getConfigurationContext();

    // check the env - whether clustered  or not
    boolean isClusteringEnable = false;
    ClusteringAgent clusteringAgent = null;
    if (cc != null) {
      clusteringAgent = cc.getAxisConfiguration().getClusteringAgent();
    }
    if (clusteringAgent != null && clusteringAgent.getStateManager() != null) {
      isClusteringEnable = true;
    }

    // Get the concurrent access controller
    ConcurrentAccessController cac;
    String key = null;
    if (isClusteringEnable) {
      // for clustered  env.,gets it from axis configuration context
      key = ThrottleConstants.THROTTLE_PROPERTY_PREFIX + throttleId + ThrottleConstants.CAC_SUFFIX;
      cac = (ConcurrentAccessController) cc.getProperty(key);
    } else {
      // for non-clustered  env.,gets it from axis configuration context
      cac = throttle.getConcurrentAccessController();
    }

    // check for concurrent access
    boolean canAccess = doConcurrentThrottling(cac, messageContext);

    if (canAccess) {
      // if the concurrent access is success then
      // do the access rate based throttling

      if (messageContext.getFLOW() == MessageContext.IN_FLOW) {
        // gets the remote caller domain name
        String domain = null;
        HttpServletRequest request =
            (HttpServletRequest)
                messageContext.getPropertyNonReplicable(HTTPConstants.MC_HTTP_SERVLETREQUEST);
        if (request != null) {
          domain = request.getRemoteHost();
        }

        // Domain name based throttling
        // check whether a configuration has been defined for this domain name or not
        String callerId = null;
        if (domain != null) {
          // loads the ThrottleContext
          ThrottleContext context =
              throttle.getThrottleContext(ThrottleConstants.DOMAIN_BASED_THROTTLE_KEY);
          if (context != null) {
            // Loads the ThrottleConfiguration
            ThrottleConfiguration config = context.getThrottleConfiguration();
            if (config != null) {
              // check for configuration for this caller
              callerId = config.getConfigurationKeyOfCaller(domain);
              if (callerId != null) {
                // If this is a clustered env.
                if (isClusteringEnable) {
                  context.setConfigurationContext(cc);
                  context.setThrottleId(throttleId);
                }
                AccessInformation infor =
                    accessRateController.canAccess(
                        context, callerId, ThrottleConstants.DOMAIN_BASE);
                StatCollector.collect(infor, domain, ThrottleConstants.DOMAIN_BASE);

                // check for the permission for access
                if (!infor.isAccessAllowed()) {

                  // In the case of both of concurrency throttling and
                  // rate based throttling have enabled ,
                  // if the access rate less than maximum concurrent access ,
                  // then it is possible to occur death situation.To avoid that reset,
                  // 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 {
                        if (debugOn) {
                          log.debug(
                              "Going to replicates the "
                                  + "states of the ConcurrentAccessController"
                                  + " with key : "
                                  + key);
                        }
                        Replicator.replicate(cc, new String[] {key});
                      } catch (ClusteringFault clusteringFault) {
                        log.error("Error during replicating states ", clusteringFault);
                      }
                    }
                  }
                  throw new AxisFault(
                      " Access deny for a "
                          + "caller with Domain "
                          + domain
                          + " "
                          + " : Reason : "
                          + infor.getFaultReason());
                }
              } else {
                if (debugOn) {
                  log.debug(
                      "Could not find the Throttle Context for domain-Based "
                          + "Throttling for domain name "
                          + domain
                          + " Throttling for this "
                          + "domain name may not be configured from policy");
                }
              }
            }
          }
        } else {
          if (debugOn) {
            log.debug("Could not find the domain of the caller - IP-based throttling may occur");
          }
        }

        // IP based throttling - Only if there is no configuration for caller domain name

        if (callerId == null) {
          String ip = (String) messageContext.getProperty(MessageContext.REMOTE_ADDR);
          if (ip != null) {
            // loads IP based throttle context
            ThrottleContext context =
                throttle.getThrottleContext(ThrottleConstants.IP_BASED_THROTTLE_KEY);
            if (context != null) {
              // Loads the ThrottleConfiguration
              ThrottleConfiguration config = context.getThrottleConfiguration();
              if (config != null) {
                // check for configuration for this ip
                callerId = config.getConfigurationKeyOfCaller(ip);
                if (callerId != null) {
                  // for clustered env.
                  if (isClusteringEnable) {
                    context.setConfigurationContext(cc);
                    context.setThrottleId(throttleId);
                  }
                  AccessInformation infor =
                      accessRateController.canAccess(context, callerId, ThrottleConstants.IP_BASE);
                  // check for the permission for access
                  StatCollector.collect(infor, ip, ThrottleConstants.IP_BASE);
                  if (!infor.isAccessAllowed()) {

                    // In the case of both of concurrency throttling and
                    // rate based throttling have enabled ,
                    // if the access rate less than maximum concurrent access ,
                    // then it is possible to occur death situation.To avoid that reset,
                    // 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 {
                          if (debugOn) {
                            log.debug(
                                "Going to replicates the "
                                    + "states of the ConcurrentAccessController"
                                    + " with key : "
                                    + key);
                          }
                          Replicator.replicate(cc, new String[] {key});
                        } catch (ClusteringFault clusteringFault) {
                          log.error("Error during replicating states ", clusteringFault);
                        }
                      }
                    }
                    throw new AxisFault(
                        " Access deny for a "
                            + "caller with IP "
                            + ip
                            + " "
                            + " : Reason : "
                            + infor.getFaultReason());
                  }
                }
              }
            } else {
              if (debugOn) {
                log.debug("Could not find the throttle Context for IP-Based throttling");
              }
            }
          } else {
            if (debugOn) {
              log.debug(
                  "Could not find the IP address of the caller " + "- throttling will not occur");
            }
          }
        }
      }
      // all the replication functionality of the access rate based throttling handles by itself
      // just replicate the current state of ConcurrentAccessController
      if (isClusteringEnable && cac != null) {
        try {
          if (debugOn) {
            log.debug(
                "Going to replicates the states of the ConcurrentAccessController"
                    + " with key : "
                    + key);
          }
          Replicator.replicate(cc, new String[] {key});
        } catch (ClusteringFault clusteringFault) {
          log.error("Error during replicating states ", clusteringFault);
        }
      }

      // finally engage rolebased access throttling if available
      doRoleBasedAccessThrottling(throttle, messageContext, isClusteringEnable);
    } else {
      // replicate the current state of ConcurrentAccessController
      if (isClusteringEnable) {
        try {
          if (debugOn) {
            log.debug(
                "Going to replicates the states of the ConcurrentAccessController"
                    + " with key : "
                    + key);
          }
          Replicator.replicate(cc, new String[] {key});
        } catch (ClusteringFault clusteringFault) {
          log.error("Error during replicating states ", clusteringFault);
        }
      }
      throw new AxisFault(
          "Access has currently been denied since " + " maximum concurrent access have exceeded");
    }
  }
  /**
   * To verify access if unit time has already over
   *
   * @param configuration -The Configuration for this caller
   * @param throttleContext -The Throttle that caller having pass
   * @param currentTime -The system current time
   * @return boolean -The boolean value which say access will allow or not
   */
  private boolean canAccessIfUnitTimeOver(
      CallerConfiguration configuration, ThrottleContext throttleContext, long currentTime) {

    boolean canAccess = false;
    // if number of access for a unit time is less than MAX and
    // if the unit time period (session time) has just over
    int maxRequest = configuration.getMaximumRequestPerUnitTime();
    if (maxRequest != 0) {
      if ((this.globalCount.get() + this.localCount.get()) < maxRequest) {
        if (this.nextTimeWindow != 0) {
          // Removes and sends the current state to others  (clustered env)
          throttleContext.removeAndFlushCaller(this.id);
        }
        if (log.isDebugEnabled()) {
          log.debug(
              "CallerContext Checking access if unit time over next time window>> Access allowed="
                  + maxRequest
                  + " available="
                  + (maxRequest - (this.globalCount.get() + this.localCount.get()))
                  + " key="
                  + this.getId()
                  + " currentGlobalCount="
                  + globalCount
                  + " currentTime="
                  + currentTime
                  + " nextTimeWindow="
                  + this.nextTimeWindow
                  + " currentLocalCount="
                  + localCount
                  + " Tier="
                  + configuration.getID()
                  + " nextAccessTime="
                  + this.nextAccessTime);
        }
        canAccess = true; // this is bonus access
        // next time callers can access as a new one
      } else {
        // if number of access for a unit time has just been greater than MAX now same as a new
        // session
        // OR if caller in prohibit session  and prohibit period has just over
        if ((this.nextAccessTime == 0) || (this.nextAccessTime <= currentTime)) {
          if (log.isDebugEnabled()) {
            log.debug(
                "CallerContext Checking access if unit time over>> Access allowed="
                    + maxRequest
                    + " available="
                    + (maxRequest - (this.globalCount.get() + this.localCount.get()))
                    + " key="
                    + this.getId()
                    + " currentGlobalCount="
                    + globalCount
                    + " currentTime="
                    + currentTime
                    + " nextTimeWindow="
                    + this.nextTimeWindow
                    + " currentLocalCount="
                    + localCount
                    + " Tier="
                    + configuration.getID()
                    + " nextAccessTime="
                    + this.nextAccessTime);
          }
          // remove previous callercontext instance
          if (this.nextTimeWindow != 0) {
            throttleContext.removeCallerContext(id);
          }
          // reset the states so that, this is the first access
          this.nextAccessTime = 0;
          canAccess = true;

          this.globalCount.set(0); // can access the system   and this is same as first access
          this.localCount.set(1);
          this.firstAccessTime = currentTime;
          this.nextTimeWindow = currentTime + configuration.getUnitTime();
          // registers caller and send the current state to others (clustered env)
          throttleContext.addAndFlushCallerContext(this, id);
          throttleContext.replicateTimeWindow(this.id);

          if (log.isDebugEnabled()) {
            log.debug(
                "Caller="
                    + this.getId()
                    + " has reset counters and added for replication when unit "
                    + "time is over");
          }
        } else {
          // if  caller in prohibit session  and prohibit period has not  over
          if (log.isDebugEnabled()) {
            String type =
                ThrottleConstants.IP_BASE == configuration.getType() ? "IP address" : "domain";
            log.debug(
                "Even unit time has over , CallerContext in prohibit state :"
                    + type
                    + " - "
                    + this.id);
          }
        }
      }
    }
    return canAccess;
  }
  /**
   * To verify access if the unit time has already not over
   *
   * @param configuration - -The Configuration for this caller
   * @param throttleContext -The Throttle Context
   * @param currentTime -The system current time
   * @return boolean -The boolean value which say access will allow or not
   */
  private boolean canAccessIfUnitTimeNotOver(
      CallerConfiguration configuration, ThrottleContext throttleContext, long currentTime) {
    boolean canAccess = false;
    int maxRequest = configuration.getMaximumRequestPerUnitTime();
    if (maxRequest != 0) {
      if ((this.globalCount.get() + this.localCount.get())
          < maxRequest) { // If the globalCount is less than max request
        if (log.isDebugEnabled()) {
          log.debug(
              "CallerContext Checking access if unit time is not over and less than max count>> Access "
                  + "allowed="
                  + maxRequest
                  + " available="
                  + (maxRequest - (this.globalCount.get() + this.localCount.get()))
                  + " key="
                  + this.getId()
                  + " currentGlobalCount="
                  + globalCount
                  + " currentTime="
                  + currentTime
                  + " "
                  + "nextTimeWindow="
                  + this.nextTimeWindow
                  + " currentLocalCount="
                  + localCount
                  + " Tier="
                  + configuration.getID()
                  + " nextAccessTime="
                  + this.nextAccessTime);
        }
        canAccess = true; // can continue access
        this.localCount.incrementAndGet();
        // Send the current state to others (clustered env)
        throttleContext.flushCallerContext(this, id);
        // can complete access

      } else {
        // else , if caller has not already prohibit
        if (this.nextAccessTime == 0) {
          // and if there is no prohibit time  period in configuration
          long prohibitTime = configuration.getProhibitTimePeriod();
          if (prohibitTime == 0) {
            // prohibit access until unit time period is over
            this.nextAccessTime = this.firstAccessTime + configuration.getUnitTime();
          } else {
            // if there is a prohibit time period in configuration ,then
            // set it as prohibit period
            this.nextAccessTime = currentTime + prohibitTime;
          }
          if (log.isDebugEnabled()) {
            String type =
                ThrottleConstants.IP_BASE == configuration.getType() ? "IP address" : "domain";
            log.debug(
                "Maximum Number of requests are reached for caller with " + type + " - " + this.id);
          }
          // Send the current state to others (clustered env)
          throttleContext.flushCallerContext(this, id);
        } else {
          // else , if the caller has already prohibit and prohibit
          // time period has already over
          if (this.nextAccessTime <= currentTime) {
            if (log.isDebugEnabled()) {
              log.debug(
                  "CallerContext Checking access if unit time is not over before time window exceed >> "
                      + "Access allowed="
                      + maxRequest
                      + " available="
                      + (maxRequest - (this.globalCount.get() + this.localCount.get()))
                      + " key="
                      + this.getId()
                      + " currentGlobalCount="
                      + globalCount
                      + " currentTime="
                      + currentTime
                      + " "
                      + "nextTimeWindow="
                      + this.nextTimeWindow
                      + " currentLocalCount="
                      + localCount
                      + " "
                      + "Tier="
                      + configuration.getID()
                      + " nextAccessTime="
                      + this.nextAccessTime);
            }
            // remove previous caller context
            if (this.nextTimeWindow != 0) {
              throttleContext.removeCallerContext(id);
            }
            // reset the states so that, this is the first access
            this.nextAccessTime = 0;
            canAccess = true;

            this.globalCount.set(0); // can access the system   and this is same as first access
            this.localCount.set(1);
            this.firstAccessTime = currentTime;
            this.nextTimeWindow = currentTime + configuration.getUnitTime();
            throttleContext.addAndFlushCallerContext(this, this.id);
            throttleContext.replicateTimeWindow(this.id);

            if (log.isDebugEnabled()) {
              log.debug(
                  "Caller="
                      + this.getId()
                      + " has reset counters and added for replication when unit "
                      + "time is not over");
            }
          } else {
            if (log.isDebugEnabled()) {
              String type =
                  ThrottleConstants.IP_BASE == configuration.getType() ? "IP address" : "domain";
              log.debug(
                  "Prohibit period is not yet over for caller with " + type + " - " + this.id);
            }
          }
        }
      }
    }
    return canAccess;
  }