package io.dropwizard.auth;

import com.google.common.base.Preconditions;

import javax.annotation.Priority;
import javax.ws.rs.Priorities;
import javax.ws.rs.container.ContainerRequestFilter;
import java.security.Principal;

@Priority(Priorities.AUTHENTICATION)
public abstract class AuthFilter<C, P extends Principal> implements ContainerRequestFilter {

    protected String prefix;
    protected String realm;
    protected Authenticator<C, P> authenticator;
    protected Authorizer<P> authorizer;
    protected UnauthorizedHandler unauthorizedHandler = new DefaultUnauthorizedHandler();

    /**
     * Abstract builder for auth filters.
     *
     * @param <C> the type of credentials that the filter accepts
     * @param <P> the type of the principal that the filter accepts
     */
    public abstract static class AuthFilterBuilder<C, P extends Principal, T extends AuthFilter<C, P>> {

        private String realm = "realm";
        private String prefix = "Basic";
        private Authenticator<C, P> authenticator;
        private Authorizer<P> authorizer = new PermitAllAuthorizer<>();

        /**
         * Sets the given realm
         *
         * @param realm a realm
         * @return the current builder
         */
        public AuthFilterBuilder<C, P, T> setRealm(String realm) {
            this.realm = realm;
            return this;
        }

        /**
         * Sets the given prefix
         *
         * @param prefix a prefix
         * @return the current builder
         */
        public AuthFilterBuilder<C, P, T> setPrefix(String prefix) {
            this.prefix = prefix;
            return this;
        }

        /**
         * Sets the given authorizer
         *
         * @param authorizer an {@link Authorizer}
         * @return the current builder
         */
        public AuthFilterBuilder<C, P, T> setAuthorizer(Authorizer<P> authorizer) {
            this.authorizer = authorizer;
            return this;
        }

        /**
         * Sets the given authenticator
         *
         * @param authenticator an {@link Authenticator}
         * @return the current builder
         */
        public AuthFilterBuilder<C, P, T> setAuthenticator(Authenticator<C, P> authenticator) {
            this.authenticator = authenticator;
            return this;
        }

        /**
         * Builds an instance of the filter with a provided authenticator,
         * an authorizer, a prefix, and a realm.
         *
         * @return a new instance of the filter
         */
        public T buildAuthFilter() {
            Preconditions.checkArgument(realm != null, "Realm is not set");
            Preconditions.checkArgument(prefix != null, "Prefix is not set");
            Preconditions.checkArgument(authenticator != null, "Authenticator is not set");
            Preconditions.checkArgument(authorizer != null, "Authorizer is not set");

            T authFilter = newInstance();
            authFilter.authorizer = authorizer;
            authFilter.authenticator = authenticator;
            authFilter.prefix = prefix;
            authFilter.realm = realm;
            return authFilter;
        }

        protected abstract T newInstance();
    }
}

@@ -553,45 +553,10 @@
 dler
- = new DefaultUnauthorizedHandler()
 ;%0A
+
 %0A   
@@ -1060,16 +1060,108 @@
 zer%3C%3E();
+%0A        private UnauthorizedHandler unauthorizedHandler = new DefaultUnauthorizedHandler();
 %0A%0A      
@@ -2374,32 +2374,426 @@
 his;%0A        %7D%0A%0A
+        /**%0A         * Sets the given unauthorized handler%0A         *%0A         * @param unauthorizedHandler an %7B@link UnauthorizedHandler%7D%0A         * @return the current builder%0A         */%0A        public AuthFilterBuilder%3CC, P, T%3E setUnauthorizedHandler(UnauthorizedHandler unauthorizedHandler) %7B%0A            this.unauthorizedHandler = unauthorizedHandler;%0A            return this;%0A        %7D%0A%0A
         /**%0A    
@@ -3351,16 +3351,121 @@
 t set%22);
+%0A            Preconditions.checkArgument(unauthorizedHandler != null, %22Unauthorized handler is not set%22);
 %0A%0A      
@@ -3634,32 +3634,32 @@
 refix = prefix;%0A
-
             auth
@@ -3672,32 +3672,98 @@
 .realm = realm;%0A
+            authFilter.unauthorizedHandler = unauthorizedHandler;%0A
             retu

Allow a hook for UnauthorizedHandler to be customized.