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.security;
019    
020    import java.net.InetAddress;
021    import java.net.UnknownHostException;
022    import java.util.Map;
023    import java.util.TreeMap;
024    
025    import javax.security.sasl.Sasl;
026    
027    import org.apache.commons.logging.Log;
028    import org.apache.commons.logging.LogFactory;
029    import org.apache.hadoop.conf.Configuration;
030    import org.apache.hadoop.security.SaslPropertiesResolver;
031    import org.apache.hadoop.security.SaslRpcServer.QualityOfProtection;
032    import org.apache.hadoop.util.CombinedIPWhiteList;
033    import org.apache.hadoop.util.StringUtils;
034    
035    
036    /**
037     * An implementation of the SaslPropertiesResolver.
038     * Uses a white list of IPs.
039     * If the connection's IP address is in the list of IP addresses, the salProperties
040     * will be unchanged.
041     * If the connection's IP is not in the list of IP addresses, then QOP for the
042     * connection will be restricted to "hadoop.rpc.protection.non-whitelist"
043     *
044     * Uses 3 IPList implementations together to form an aggregate whitelist.
045     * 1. ConstantIPList - to check against a set of hardcoded IPs
046     * 2. Fixed IP List - to check against a list of IP addresses which are specified externally, but
047     * will not change over runtime.
048     * 3. Variable IP List - to check against a list of IP addresses which are specified externally and
049     * could change during runtime.
050     * A connection IP address will checked against these 3 IP Lists in the order specified above.
051     * Once a match is found , the IP address is determined to be in whitelist.
052     *
053     * The behavior can be configured using a bunch of configuration parameters.
054     *
055     */
056    public class WhitelistBasedResolver extends SaslPropertiesResolver {
057      public static final Log LOG = LogFactory.getLog(WhitelistBasedResolver.class);
058    
059      private static final String FIXEDWHITELIST_DEFAULT_LOCATION = "/etc/hadoop/fixedwhitelist";
060    
061      private static final String VARIABLEWHITELIST_DEFAULT_LOCATION = "/etc/hadoop/whitelist";
062    
063      /**
064       * Path to the file to containing subnets and ip addresses to form fixed whitelist.
065       */
066      public static final String HADOOP_SECURITY_SASL_FIXEDWHITELIST_FILE =
067        "hadoop.security.sasl.fixedwhitelist.file";
068      /**
069       * Enables/Disables variable whitelist
070       */
071      public static final String HADOOP_SECURITY_SASL_VARIABLEWHITELIST_ENABLE =
072        "hadoop.security.sasl.variablewhitelist.enable";
073      /**
074       * Path to the file to containing subnets and ip addresses to form variable whitelist.
075       */
076      public static final String HADOOP_SECURITY_SASL_VARIABLEWHITELIST_FILE =
077        "hadoop.security.sasl.variablewhitelist.file";
078      /**
079       * time in seconds by which the variable whitelist file is checked for updates
080       */
081      public static final String HADOOP_SECURITY_SASL_VARIABLEWHITELIST_CACHE_SECS =
082        "hadoop.security.sasl.variablewhitelist.cache.secs";
083    
084      /**
085       * comma separated list containing alternate hadoop.rpc.protection values for
086       * clients which are not in whitelist
087       */
088      public static final String HADOOP_RPC_PROTECTION_NON_WHITELIST =
089        "hadoop.rpc.protection.non-whitelist";
090    
091      private CombinedIPWhiteList whiteList;
092    
093      private Map<String, String> saslProps;
094    
095      @Override
096      public void setConf(Configuration conf) {
097        super.setConf(conf);
098        String fixedFile = conf.get(HADOOP_SECURITY_SASL_FIXEDWHITELIST_FILE,
099            FIXEDWHITELIST_DEFAULT_LOCATION);
100        String variableFile = null;
101        long expiryTime = 0;
102    
103        if (conf.getBoolean(HADOOP_SECURITY_SASL_VARIABLEWHITELIST_ENABLE, false)) {
104          variableFile = conf.get(HADOOP_SECURITY_SASL_VARIABLEWHITELIST_FILE,
105              VARIABLEWHITELIST_DEFAULT_LOCATION);
106          expiryTime =
107            conf.getLong(HADOOP_SECURITY_SASL_VARIABLEWHITELIST_CACHE_SECS,3600) * 1000;
108        }
109    
110        whiteList = new CombinedIPWhiteList(fixedFile,variableFile,expiryTime);
111    
112        this.saslProps = getSaslProperties(conf);
113      }
114    
115      /**
116       * Identify the Sasl Properties to be used for a connection with a client.
117       * @param clientAddress client's address
118       * @return the sasl properties to be used for the connection.
119       */
120      @Override
121      public Map<String, String> getServerProperties(InetAddress clientAddress) {
122        if (clientAddress == null) {
123          return saslProps;
124        }
125        return  whiteList.isIn(clientAddress.getHostAddress())?getDefaultProperties():saslProps;
126      }
127    
128      public Map<String, String> getServerProperties(String clientAddress) throws UnknownHostException {
129        if (clientAddress == null) {
130          return saslProps;
131        }
132        return getServerProperties(InetAddress.getByName(clientAddress));
133      }
134    
135      static Map<String, String> getSaslProperties(Configuration conf) {
136        Map<String, String> saslProps =new TreeMap<String, String>();
137        String[] qop = conf.getStrings(HADOOP_RPC_PROTECTION_NON_WHITELIST,
138            QualityOfProtection.PRIVACY.toString());
139    
140        for (int i=0; i < qop.length; i++) {
141          qop[i] = QualityOfProtection.valueOf(qop[i].toUpperCase()).getSaslQop();
142        }
143    
144        saslProps.put(Sasl.QOP, StringUtils.join(",", qop));
145        saslProps.put(Sasl.SERVER_AUTH, "true");
146    
147        return saslProps;
148      }
149    }