Package org.apache.falcon.security

Source Code of org.apache.falcon.security.BasicAuthFilter

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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 org.apache.falcon.security;

import org.apache.commons.lang.StringUtils;
import org.apache.falcon.util.StartupProperties;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
import org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler;
import org.apache.log4j.Logger;
import org.apache.log4j.NDC;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.UUID;

/**
* This enforces authentication as part of the filter before processing the request.
* Subclass of {@link AuthenticationFilter}.
*/
public class BasicAuthFilter extends AuthenticationFilter {

    private static final Logger LOG = Logger.getLogger(BasicAuthFilter.class);

    /**
     * Constant for the configuration property that indicates the prefix.
     */
    protected static final String FALCON_PREFIX = "falcon.http.authentication.";
    protected static final String KERBEROS_PRINCIPAL = FALCON_PREFIX + KerberosAuthenticationHandler.PRINCIPAL;

    /**
     * Constant for the configuration property that indicates the blacklisted super users for falcon.
     */
    private static final String BLACK_LISTED_USERS_KEY = FALCON_PREFIX + "blacklisted.users";

    /**
     * An options servlet is used to authenticate users. OPTIONS method is used for triggering authentication
     * before invoking the actual resource.
     */
    private HttpServlet optionsServlet;
    private Set<String> blackListedUsers;

    /**
     * Initialize the filter.
     *
     * @param filterConfig filter configuration.
     * @throws ServletException thrown if the filter could not be initialized.
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        LOG.info("BasicAuthFilter initialization started");
        super.init(filterConfig);

        optionsServlet = new HttpServlet() {};
        optionsServlet.init();

        initializeBlackListedUsers();
    }

    private void initializeBlackListedUsers() {
        blackListedUsers = new HashSet<String>();
        String blackListedUserConfig = StartupProperties.get().getProperty(BLACK_LISTED_USERS_KEY);
        if (!StringUtils.isEmpty(blackListedUserConfig)) {
            blackListedUsers.addAll(Arrays.asList(blackListedUserConfig.split(",")));
        }
    }

    /**
     * Returns the configuration from Oozie configuration to be used by the authentication filter.
     * <p/>
     * All properties from Oozie configuration which name starts with {@link #FALCON_PREFIX} will
     * be returned. The keys of the returned properties are trimmed from the {@link #FALCON_PREFIX}
     * prefix, for example the Oozie configuration property name 'oozie.authentication.type' will
     * be just 'type'.
     *
     * @param configPrefix configuration prefix, this parameter is ignored by this implementation.
     * @param filterConfig filter configuration, this parameter is ignored by this implementation.
     * @return all Oozie configuration properties prefixed with {@link #FALCON_PREFIX}, without the
     * prefix.
     */
    @Override
    protected Properties getConfiguration(String configPrefix, FilterConfig filterConfig) {
        Properties authProperties = new Properties();
        Properties configProperties = StartupProperties.get();

        // setting the cookie path to root '/' so it is used for all resources.
        authProperties.setProperty(AuthenticationFilter.COOKIE_PATH, "/");

        for (Map.Entry entry : configProperties.entrySet()) {
            String name = (String) entry.getKey();
            if (name.startsWith(FALCON_PREFIX)) {
                String value = (String) entry.getValue();
                name = name.substring(FALCON_PREFIX.length());
                authProperties.setProperty(name, value);
            }
        }

        if (UserGroupInformation.isSecurityEnabled()) { // replace _HOST in principal
            String principal = getKerberosPrincipalWithSubstitutedHost(configProperties);
            // principal cannot be null in secure mode, is validated in submission
            authProperties.setProperty(KerberosAuthenticationHandler.PRINCIPAL, principal);
        }

        return authProperties;
    }

    /**
     * Replaces _HOST in the principal with the actual hostname.
     *
     * @param configProperties Falcon config properties
     * @return principal with _HOST substituted
     */
    private String getKerberosPrincipalWithSubstitutedHost(Properties configProperties) {
        String principal = configProperties.getProperty(KERBEROS_PRINCIPAL);
        try {
            principal = org.apache.hadoop.security.SecurityUtil.getServerPrincipal(
                    principal, SecurityUtil.getLocalHostName());
        } catch (IOException ignored) {
            // do nothing
        }

        return principal;
    }

    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response,
                         final FilterChain filterChain) throws IOException, ServletException {

        FilterChain filterChainWrapper = new FilterChain() {

            @Override
            public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse)
                throws IOException, ServletException {
                HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;

                if (httpRequest.getMethod().equals("OPTIONS")) { // option request meant only for authentication
                    optionsServlet.service(request, response);
                } else {
                    final String user = getUserFromRequest(httpRequest);
                    if (StringUtils.isEmpty(user)) {
                        ((HttpServletResponse) response).sendError(Response.Status.BAD_REQUEST.getStatusCode(),
                                "User can't be empty");
                    } else if (blackListedUsers.contains(user)) {
                        ((HttpServletResponse) response).sendError(Response.Status.BAD_REQUEST.getStatusCode(),
                                "User can't be a superuser:" + BLACK_LISTED_USERS_KEY);
                    } else {
                        try {
                            String requestId = UUID.randomUUID().toString();
                            NDC.push(user + ":" + httpRequest.getMethod() + "/" + httpRequest.getPathInfo());
                            NDC.push(requestId);
                            CurrentUser.authenticate(user);
                            LOG.info("Request from user: " + user + ", URL=" + getRequestUrl(httpRequest));

                            filterChain.doFilter(servletRequest, servletResponse);
                        } finally {
                            NDC.pop();
                            NDC.pop();
                        }
                    }
                }
            }

            private String getUserFromRequest(HttpServletRequest httpRequest) {
                String user = httpRequest.getRemoteUser(); // this is available from wrapper in super class
                if (!StringUtils.isEmpty(user)) {
                    return user;
                }

                user = httpRequest.getParameter("user.name"); // available in query-param
                if (!StringUtils.isEmpty(user)) {
                    return user;
                }

                user = httpRequest.getHeader("Remote-User"); // backwards-compatibility
                if (!StringUtils.isEmpty(user)) {
                    return user;
                }

                return null;
            }

            private String getRequestUrl(HttpServletRequest request) {
                StringBuffer url = request.getRequestURL();
                if (request.getQueryString() != null) {
                    url.append("?").append(request.getQueryString());
                }

                return url.toString();
            }
        };

        super.doFilter(request, response, filterChainWrapper);
    }

    @Override
    public void destroy() {
        if (optionsServlet != null) {
            optionsServlet.destroy();
        }

        super.destroy();
    }
}
TOP

Related Classes of org.apache.falcon.security.BasicAuthFilter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.