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 org.apache.hadoop.http.HttpServer;
021    import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
022    import org.apache.hadoop.conf.Configuration;
023    import org.apache.hadoop.http.FilterContainer;
024    import org.apache.hadoop.http.FilterInitializer;
025    import org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler;
026    
027    import java.io.FileReader;
028    import java.io.IOException;
029    import java.io.Reader;
030    import java.util.HashMap;
031    import java.util.Map;
032    
033    /**
034     * Initializes hadoop-auth AuthenticationFilter which provides support for
035     * Kerberos HTTP SPNEGO authentication.
036     * <p/>
037     * It enables anonymous access, simple/speudo and Kerberos HTTP SPNEGO
038     * authentication  for Hadoop JobTracker, NameNode, DataNodes and
039     * TaskTrackers.
040     * <p/>
041     * Refer to the <code>core-default.xml</code> file, after the comment
042     * 'HTTP Authentication' for details on the configuration options.
043     * All related configuration properties have 'hadoop.http.authentication.'
044     * as prefix.
045     */
046    public class AuthenticationFilterInitializer extends FilterInitializer {
047    
048      static final String PREFIX = "hadoop.http.authentication.";
049    
050      static final String SIGNATURE_SECRET_FILE = AuthenticationFilter.SIGNATURE_SECRET + ".file";
051    
052      /**
053       * Initializes hadoop-auth AuthenticationFilter.
054       * <p/>
055       * Propagates to hadoop-auth AuthenticationFilter configuration all Hadoop
056       * configuration properties prefixed with "hadoop.http.authentication."
057       *
058       * @param container The filter container
059       * @param conf Configuration for run-time parameters
060       */
061      @Override
062      public void initFilter(FilterContainer container, Configuration conf) {
063        Map<String, String> filterConfig = new HashMap<String, String>();
064    
065        //setting the cookie path to root '/' so it is used for all resources.
066        filterConfig.put(AuthenticationFilter.COOKIE_PATH, "/");
067    
068        for (Map.Entry<String, String> entry : conf) {
069          String name = entry.getKey();
070          if (name.startsWith(PREFIX)) {
071            String value = conf.get(name);
072            name = name.substring(PREFIX.length());
073            filterConfig.put(name, value);
074          }
075        }
076    
077        String signatureSecretFile = filterConfig.get(SIGNATURE_SECRET_FILE);
078        if (signatureSecretFile == null) {
079          throw new RuntimeException("Undefined property: " + SIGNATURE_SECRET_FILE);      
080        }
081        
082        try {
083          StringBuilder secret = new StringBuilder();
084          Reader reader = new FileReader(signatureSecretFile);
085          int c = reader.read();
086          while (c > -1) {
087            secret.append((char)c);
088            c = reader.read();
089          }
090          reader.close();
091          filterConfig.put(AuthenticationFilter.SIGNATURE_SECRET, secret.toString());
092        } catch (IOException ex) {
093          throw new RuntimeException("Could not read HTTP signature secret file: " + signatureSecretFile);            
094        }
095    
096        //Resolve _HOST into bind address
097        String bindAddress = conf.get(HttpServer.BIND_ADDRESS);
098        String principal = filterConfig.get(KerberosAuthenticationHandler.PRINCIPAL);
099        if (principal != null) {
100          try {
101            principal = SecurityUtil.getServerPrincipal(principal, bindAddress);
102          }
103          catch (IOException ex) {
104            throw new RuntimeException("Could not resolve Kerberos principal name: " + ex.toString(), ex);
105          }
106          filterConfig.put(KerberosAuthenticationHandler.PRINCIPAL, principal);
107        }
108    
109        container.addFilter("authentication",
110                            AuthenticationFilter.class.getName(),
111                            filterConfig);
112      }
113    
114    }