package io.dropwizard.auth;

import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature;
import org.glassfish.jersey.server.model.AnnotatedMethod;

import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.DynamicFeature;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.FeatureContext;
import java.lang.annotation.Annotation;

/**
 * A {@link DynamicFeature} that registers the provided auth filter
 * to resource methods annotated with the {@link RolesAllowed}, {@link PermitAll}
 * and {@link DenyAll} annotations.
 * <p>In conjunction with {@link RolesAllowedDynamicFeature} it enables
 * authorization <i>AND</i> authentication of requests on the annotated methods.</p>
 * <p>If authorization is not a concern, then {@link RolesAllowedDynamicFeature}
 * could be omitted. But to enable authentication, the {@link PermitAll} annotation
 * should be placed on the corresponding resource methods.</p>
 */
public class AuthDynamicFeature implements DynamicFeature {

    private final ContainerRequestFilter authFilter;

    public AuthDynamicFeature(ContainerRequestFilter authFilter) {
        this.authFilter = authFilter;
    }

    @Override
    public void configure(ResourceInfo resourceInfo, FeatureContext context) {
        final AnnotatedMethod am = new AnnotatedMethod(resourceInfo.getResourceMethod());
        final Annotation[][] parameterAnnotations = am.getParameterAnnotations();
        //@DenyAll shouldn't be attached to classes
        final boolean annotationOnClass = (resourceInfo.getResourceClass().getAnnotation(RolesAllowed.class) != null) ||
            (resourceInfo.getResourceClass().getAnnotation(PermitAll.class) != null);
        final boolean annotationOnMethod = am.isAnnotationPresent(RolesAllowed.class) || am.isAnnotationPresent(DenyAll.class) ||
            am.isAnnotationPresent(PermitAll.class);

        if (annotationOnClass || annotationOnMethod) {
            context.register(authFilter);
        } else {
            for (Annotation[] annotations : parameterAnnotations) {
                for (Annotation annotation : annotations) {
                    if (annotation instanceof Auth) {
                        context.register(authFilter);
                        return;
                    }
                }
            }
        }
    }
}

@@ -1085,12 +1085,416 @@
 /p%3E%0A
+ * %3Cp%3ENote that registration of the filter will follow the semantics of%0A * %7B@link FeatureContext#register(Class)%7D and %7B@link FeatureContext#register(Object)%7D:%0A * passing the filter as a %7B@link Class%7D to the %7B@link #AuthDynamicFeature(Class)%7D%0A * constructor will result in dependency injection, while objects passed to%0A * the %7B@link #AuthDynamicFeature(ContainerRequestFilter)%7D will be used directly.%3C/p%3E%0A
  */%0A
-
 publ
@@ -1604,16 +1604,92 @@
 ilter;%0A%0A
+    private final Class%3C? extends ContainerRequestFilter%3E authFilterClass;%0A%0A
     publ
@@ -1785,16 +1785,229 @@
 Filter;%0A
+        this.authFilterClass = null;%0A    %7D%0A%0A    public AuthDynamicFeature(Class%3C? extends ContainerRequestFilter%3E authFilterClass) %7B%0A        this.authFilter = null;%0A        this.authFilterClass = authFilterClass;%0A
     %7D%0A%0A 
@@ -2780,32 +2780,24 @@
         
-context.
 register
 (authFil
@@ -2780,34 +2780,33 @@
         register
-(a
+A
 uthFilter);%0A    
@@ -2790,32 +2790,40 @@
 gisterAuthFilter
+(context
 );%0A        %7D els
@@ -3036,24 +3036,16 @@
     
-context.
 register
 (aut
@@ -3040,18 +3040,17 @@
 register
-(a
+A
 uthFilte
@@ -3050,16 +3050,24 @@
 thFilter
+(context
 );%0A     
@@ -3125,32 +3125,32 @@
               %7D%0A
-
             %7D%0A  
@@ -3162,11 +3162,259 @@
  %7D%0A    %7D
+%0A%0A    private void registerAuthFilter(FeatureContext context) %7B%0A        if (authFilter != null) %7B%0A            context.register(authFilter);%0A        %7D else if (authFilterClass != null) %7B%0A            context.register(authFilterClass);%0A        %7D%0A    %7D
 %0A%7D%0A

Allow for passing a filter as a class to AuthDynamicFeature (#1715)