View Javadoc

1   package com.atlassian.plugins.rest.common.feature.jersey;
2   
3   import com.atlassian.plugins.rest.common.feature.RequiresDarkFeature;
4   import com.atlassian.sal.api.features.DarkFeatureManager;
5   import com.sun.jersey.api.NotFoundException;
6   import com.sun.jersey.api.model.AbstractMethod;
7   import com.sun.jersey.spi.container.ContainerRequest;
8   import com.sun.jersey.spi.container.ContainerRequestFilter;
9   import com.sun.jersey.spi.container.ContainerResponseFilter;
10  import com.sun.jersey.spi.container.ResourceFilter;
11  import org.slf4j.Logger;
12  import org.slf4j.LoggerFactory;
13  
14  import java.lang.reflect.AnnotatedElement;
15  import javax.annotation.Nonnull;
16  
17  import static com.atlassian.plugins.rest.common.util.ReflectionUtils.getAnnotation;
18  import static com.google.common.base.Preconditions.checkNotNull;
19  
20  /**
21   * Restricts access to resources based on the state of dark feature flags.
22   * <p>
23   * Used with the {@link RequiresDarkFeature} annotation to control access to resources and methods based on the
24   * named dark feature keys.
25   *
26   * @see RequiresDarkFeature
27   */
28  public class DarkFeatureResourceFilter implements ResourceFilter, ContainerRequestFilter {
29      private static final Logger log = LoggerFactory.getLogger(DarkFeatureResourceFilter.class);
30  
31      private final DarkFeatureManager darkFeatureManager;
32      private final AbstractMethod abstractMethod;
33  
34      public DarkFeatureResourceFilter(@Nonnull final AbstractMethod method, @Nonnull final DarkFeatureManager darkFeatureManager) {
35          this.darkFeatureManager = checkNotNull(darkFeatureManager);
36          this.abstractMethod = checkNotNull(method);
37      }
38  
39      @Override
40      public ContainerRequestFilter getRequestFilter() {
41          return this;
42      }
43  
44      @Override
45      public ContainerResponseFilter getResponseFilter() {
46          return null;
47      }
48  
49      @Override
50      public ContainerRequest filter(final ContainerRequest request) {
51          log.debug("Applying dark feature filter to request {} {}", request.getMethod(), request.getRequestUri());
52          if (accessIsAllowed(abstractMethod) && accessIsAllowed(abstractMethod.getResource())) {
53              log.debug("Dark feature check OK");
54              return request;
55          }
56          log.debug("Dark feature check failed. Refusing access to the resource.");
57  
58          throw new NotFoundException(request.getRequestUri());
59      }
60  
61      private boolean accessIsAllowed(AnnotatedElement e) {
62          if (e == null) {
63              return true;
64          }
65  
66          final RequiresDarkFeature annotation = getAnnotation(RequiresDarkFeature.class, e);
67          return annotation == null || allFeaturesAreEnabled(annotation.value());
68      }
69  
70      private boolean allFeaturesAreEnabled(String[] featureKeys) {
71          for (String featureKey : featureKeys) {
72              if (!darkFeatureManager.isFeatureEnabledForCurrentUser(featureKey)) {
73                  return false;
74              }
75          }
76          return true;
77      }
78  }