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