InternalAuthenticationFilter.java

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.facebook.presto.server.security;

import com.facebook.presto.server.InternalAuthenticationManager;

import javax.annotation.security.RolesAllowed;
import javax.inject.Inject;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;

import java.lang.reflect.Method;
import java.security.Principal;
import java.util.Arrays;
import java.util.Optional;

import static com.facebook.presto.server.security.RoleType.INTERNAL;
import static java.util.Objects.requireNonNull;
import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
import static javax.ws.rs.core.Response.ResponseBuilder;

@Provider
public class InternalAuthenticationFilter
        implements ContainerRequestFilter
{
    private final InternalAuthenticationManager internalAuthenticationManager;
    private Optional<Principal> principal = Optional.empty();

    @Context
    ResourceInfo resourceInfo;

    @Inject
    public InternalAuthenticationFilter(InternalAuthenticationManager internalAuthenticationManager)
    {
        this.internalAuthenticationManager = requireNonNull(internalAuthenticationManager, "internalAuthenticationManager is null");
    }

    public InternalAuthenticationFilter(InternalAuthenticationManager internalAuthenticationManager, ResourceInfo resourceInfo)
    {
        this.internalAuthenticationManager = requireNonNull(internalAuthenticationManager, "internalAuthenticationManager is null");
        this.resourceInfo = requireNonNull(resourceInfo, "resourceInfo is null");
    }

    public Optional<Principal> getPrincipal()
    {
        return principal;
    }

    @Override
    public void filter(ContainerRequestContext context)
    {
        if (internalAuthenticationManager.isInternalRequest(context) ||
                (internalAuthenticationManager.isInternalJwtEnabled() && isAccessingInternalEndpoint(resourceInfo))) {
            Principal authenticatedPrincipal = internalAuthenticationManager.authenticateInternalRequest(context);
            if (authenticatedPrincipal == null) {
                ResponseBuilder responseBuilder = Response.serverError();
                responseBuilder.status(SC_UNAUTHORIZED, "Unauthorized");
                context.abortWith(responseBuilder.build());
            }
            else {
                principal = Optional.of(authenticatedPrincipal);
            }
        }
    }

    private static boolean isAccessingInternalEndpoint(ResourceInfo resourceInfo)
    {
        if (resourceInfo != null) {
            Class<?> resourceClass = resourceInfo.getResourceClass();
            Method resourceMethod = resourceInfo.getResourceMethod();
            if ((resourceClass != null && resourceClass.isAnnotationPresent(RolesAllowed.class) &&
                    Arrays.asList(resourceClass.getAnnotation(RolesAllowed.class).value()).contains(INTERNAL)) ||
                    (resourceMethod != null && resourceMethod.isAnnotationPresent(RolesAllowed.class) &&
                            Arrays.asList(resourceMethod.getAnnotation(RolesAllowed.class).value()).contains(INTERNAL))) {
                return true;
            }
        }

        return false;
    }
}