public static void validateFineGrainedAuth(Method endpointMethod, UriInfo uriInfo, HttpHeaders httpHeaders,
      FineGrainedAccessControl accessControl) {
    if (endpointMethod.isAnnotationPresent(Authorize.class)) {
      final Authorize auth = endpointMethod.getAnnotation(Authorize.class);
      String targetId = null;
      // Message to use in the access denied exception
      String accessDeniedMsg;
      if (auth.targetType() == TargetType.TABLE) {
        // paramName is mandatory for table level authorization
        if (StringUtils.isEmpty(auth.paramName())) {
          throw new WebApplicationException(
              "paramName not found for table level authorization in API: " + uriInfo.getRequestUri(),
              Response.Status.INTERNAL_SERVER_ERROR);
        }

        // find the paramName in the path or query params
        targetId = findParam(auth.paramName(), uriInfo.getPathParameters(), uriInfo.getQueryParameters());

        if (StringUtils.isEmpty(targetId)) {
          throw new WebApplicationException(
              "Could not find paramName " + auth.paramName() + " in path or query params of the API: "
                  + uriInfo.getRequestUri(), Response.Status.INTERNAL_SERVER_ERROR);
        }

        // Table name may contain type, hence get raw table name for checking access
        targetId = DatabaseUtils.translateTableName(TableNameBuilder.extractRawTableName(targetId), httpHeaders);

        accessDeniedMsg = "Access denied to " + auth.action() + " for table: " + targetId;
      } else if (auth.targetType() == TargetType.CLUSTER) {
        accessDeniedMsg = "Access denied to " + auth.action() + " in the cluster";
      } else {
        throw new WebApplicationException(
            "Unsupported targetType: " + auth.targetType() + " in API: " + uriInfo.getRequestUri(),
            Response.Status.INTERNAL_SERVER_ERROR);
      }

      boolean hasAccess;
      try {
        hasAccess = accessControl.hasAccess(httpHeaders, auth.targetType(), targetId, auth.action());
      } catch (Throwable t) {
        // catch and log Throwable for NoSuchMethodError which can happen when there are classpath conflicts
        // otherwise, grizzly will return a 500 without any logs or indication of what failed
        String errorMsg = String.format("Failed to check for access for target type %s and target ID %s with action %s",
            auth.targetType(), targetId, auth.action());
        LOGGER.error(errorMsg, t);
        throw new WebApplicationException(errorMsg, t, Response.Status.INTERNAL_SERVER_ERROR);
      }

      // Check for access now
      if (!hasAccess) {
        throw new WebApplicationException(accessDeniedMsg, Response.Status.FORBIDDEN);
      }
    } else if (!accessControl.defaultAccess(httpHeaders)) {
      throw new WebApplicationException("Access denied - default authorization failed", Response.Status.FORBIDDEN);
    }
  }
@Test
  public void testValidateFineGrainedAuthAllowed() {
    FineGrainedAccessControl ac = Mockito.mock(FineGrainedAccessControl.class);
    Mockito.when(ac.hasAccess(Mockito.any(HttpHeaders.class), Mockito.any(), Mockito.any(), Mockito.any()))
        .thenReturn(true);

    UriInfo mockUriInfo = Mockito.mock(UriInfo.class);
    HttpHeaders mockHttpHeaders = Mockito.mock(HttpHeaders.class);

    FineGrainedAuthUtils.validateFineGrainedAuth(getAnnotatedMethod(), mockUriInfo, mockHttpHeaders, ac);
  }