001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *      http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    package org.apache.oozie.servlet;
019    
020    import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
021    import org.apache.hadoop.conf.Configuration;
022    import org.apache.oozie.service.Services;
023    
024    import javax.servlet.FilterChain;
025    import javax.servlet.FilterConfig;
026    import javax.servlet.ServletException;
027    import javax.servlet.ServletRequest;
028    import javax.servlet.ServletResponse;
029    import javax.servlet.http.HttpServlet;
030    import javax.servlet.http.HttpServletRequest;
031    import java.io.IOException;
032    import java.util.Map;
033    import java.util.Properties;
034    
035    /**
036     * Authentication filter that extends Hadoop-auth AuthenticationFilter to override
037     * the configuration loading.
038     */
039    public class AuthFilter extends AuthenticationFilter {
040        private static final String OOZIE_PREFIX = "oozie.authentication.";
041    
042        private HttpServlet optionsServlet;
043    
044        /**
045         * Initialize the filter.
046         *
047         * @param filterConfig filter configuration.
048         * @throws ServletException thrown if the filter could not be initialized.
049         */
050        @Override
051        public void init(FilterConfig filterConfig) throws ServletException {
052            super.init(filterConfig);
053            optionsServlet = new HttpServlet() {};
054            optionsServlet.init();
055        }
056    
057        /**
058         * Destroy the filter.
059         */
060        @Override
061        public void destroy() {
062            optionsServlet.destroy();
063            super.destroy();
064        }
065    
066        /**
067         * Returns the configuration from Oozie configuration to be used by the authentication filter.
068         * <p/>
069         * All properties from Oozie configuration which name starts with {@link #OOZIE_PREFIX} will
070         * be returned. The keys of the returned properties are trimmed from the {@link #OOZIE_PREFIX}
071         * prefix, for example the Oozie configuration property name 'oozie.authentication.type' will
072         * be just 'type'.
073         *
074         * @param configPrefix configuration prefix, this parameter is ignored by this implementation.
075         * @param filterConfig filter configuration, this parameter is ignored by this implementation.
076         * @return all Oozie configuration properties prefixed with {@link #OOZIE_PREFIX}, without the
077         * prefix.
078         */
079        @Override
080        protected Properties getConfiguration(String configPrefix, FilterConfig filterConfig) {
081            Properties props = new Properties();
082            Configuration conf = Services.get().getConf();
083    
084            //setting the cookie path to root '/' so it is used for all resources.
085            props.setProperty(AuthenticationFilter.COOKIE_PATH, "/");
086    
087            for (Map.Entry<String, String> entry : conf) {
088                String name = entry.getKey();
089                if (name.startsWith(OOZIE_PREFIX)) {
090                    String value = conf.get(name);
091                    name = name.substring(OOZIE_PREFIX.length());
092                    props.setProperty(name, value);
093                }
094            }
095    
096            return props;
097        }
098    
099        /**
100         * Enforces authentication using Hadoop-auth AuthenticationFilter.
101         * <p/>
102         * This method is overriden to respond to HTTP OPTIONS requests for authenticated calls, regardless
103         * of the target servlet supporting OPTIONS or not and to inject the authenticated user name as
104         * request attribute for Oozie to retrieve the user id.
105         *
106         * @param request http request.
107         * @param response http response.
108         * @param filterChain filter chain.
109         * @throws IOException thrown if an IO error occurs.
110         * @throws ServletException thrown if a servlet error occurs.
111         */
112        @Override
113        public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain filterChain)
114                throws IOException, ServletException {
115    
116            FilterChain filterChainWrapper = new FilterChain() {
117                @Override
118                public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse)
119                        throws IOException, ServletException {
120                    HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
121                    if (httpRequest.getMethod().equals("OPTIONS")) {
122                        optionsServlet.service(request, response);
123                    }
124                    else {
125                      httpRequest.setAttribute(JsonRestServlet.USER_NAME, httpRequest.getRemoteUser());
126                      filterChain.doFilter(servletRequest, servletResponse);
127                    }
128                }
129            };
130    
131            super.doFilter(request, response, filterChainWrapper);
132        }
133    
134    }