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.hadoop.http.lib;
019    
020    import java.io.IOException;
021    import java.security.Principal;
022    import java.util.HashMap;
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.HttpServletRequest;
030    import javax.servlet.http.HttpServletRequestWrapper;
031    
032    import org.apache.commons.logging.Log;
033    import org.apache.commons.logging.LogFactory;
034    import org.apache.hadoop.conf.Configuration;
035    import org.apache.hadoop.http.FilterContainer;
036    import org.apache.hadoop.http.FilterInitializer;
037    
038    import javax.servlet.Filter;
039    
040    import static org.apache.hadoop.fs.CommonConfigurationKeys.HADOOP_HTTP_STATIC_USER;
041    import static org.apache.hadoop.fs.CommonConfigurationKeys.DEFAULT_HADOOP_HTTP_STATIC_USER;
042    
043    /**
044     * Provides a servlet filter that pretends to authenticate a fake user (Dr.Who)
045     * so that the web UI is usable for a secure cluster without authentication.
046     */
047    public class StaticUserWebFilter extends FilterInitializer {
048      static final String DEPRECATED_UGI_KEY = "dfs.web.ugi";
049    
050      private static final Log LOG = LogFactory.getLog(StaticUserWebFilter.class);
051    
052      static class User implements Principal {
053        private final String name;
054        public User(String name) {
055          this.name = name;
056        }
057        @Override
058        public String getName() {
059          return name;
060        }
061        @Override
062        public int hashCode() {
063          return name.hashCode();
064        }
065        @Override
066        public boolean equals(Object other) {
067          if (other == this) {
068            return true;
069          } else if (other == null || other.getClass() != getClass()) {
070            return false;
071          }
072          return ((User) other).name.equals(name);
073        }
074        @Override
075        public String toString() {
076          return name;
077        }    
078      }
079    
080      public static class StaticUserFilter implements Filter {
081        private User user;
082        private String username;
083    
084        @Override
085        public void destroy() {
086          // NOTHING
087        }
088    
089        @Override
090        public void doFilter(ServletRequest request, ServletResponse response,
091                             FilterChain chain
092                             ) throws IOException, ServletException {
093          HttpServletRequest httpRequest = (HttpServletRequest) request;
094          // if the user is already authenticated, don't override it
095          if (httpRequest.getRemoteUser() != null) {
096            chain.doFilter(request, response);
097          } else {
098            HttpServletRequestWrapper wrapper = 
099                new HttpServletRequestWrapper(httpRequest) {
100              @Override
101              public Principal getUserPrincipal() {
102                return user;
103              }
104              @Override
105              public String getRemoteUser() {
106                return username;
107              }
108            };
109            chain.doFilter(wrapper, response);
110          }
111        }
112    
113        @Override
114        public void init(FilterConfig conf) throws ServletException {
115          this.username = conf.getInitParameter(HADOOP_HTTP_STATIC_USER);
116          this.user = new User(username);
117        }
118        
119      }
120    
121      @Override
122      public void initFilter(FilterContainer container, Configuration conf) {
123        HashMap<String, String> options = new HashMap<String, String>();
124        
125        String username = getUsernameFromConf(conf);
126        options.put(HADOOP_HTTP_STATIC_USER, username);
127    
128        container.addFilter("static_user_filter", 
129                            StaticUserFilter.class.getName(), 
130                            options);
131      }
132    
133      /**
134       * Retrieve the static username from the configuration.
135       */
136      static String getUsernameFromConf(Configuration conf) {
137        String oldStyleUgi = conf.get(DEPRECATED_UGI_KEY);
138        if (oldStyleUgi != null) {
139          // We can't use the normal configuration deprecation mechanism here
140          // since we need to split out the username from the configured UGI.
141          LOG.warn(DEPRECATED_UGI_KEY + " should not be used. Instead, use " + 
142              HADOOP_HTTP_STATIC_USER + ".");
143          String[] parts = oldStyleUgi.split(",");
144          return parts[0];
145        } else {
146          return conf.get(HADOOP_HTTP_STATIC_USER,
147            DEFAULT_HADOOP_HTTP_STATIC_USER);
148        }
149      }
150    
151    }