View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.security;
20  
21  import java.nio.charset.StandardCharsets;
22  import java.util.Map;
23  import java.util.TreeMap;
24  
25  import javax.security.sasl.Sasl;
26  import javax.security.sasl.SaslClient;
27  import javax.security.sasl.SaslException;
28  
29  import org.apache.commons.codec.binary.Base64;
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.hadoop.hbase.classification.InterfaceAudience;
33  import org.apache.hadoop.hbase.util.Bytes;
34  
35  @InterfaceAudience.Private
36  public class SaslUtil {
37    private static final Log LOG = LogFactory.getLog(SaslUtil.class);
38    public static final String SASL_DEFAULT_REALM = "default";
39    public static final int SWITCH_TO_SIMPLE_AUTH = -88;
40  
41    public enum QualityOfProtection {
42      AUTHENTICATION("auth"),
43      INTEGRITY("auth-int"),
44      PRIVACY("auth-conf");
45  
46      private final String saslQop;
47  
48      QualityOfProtection(String saslQop) {
49        this.saslQop = saslQop;
50      }
51  
52      public String getSaslQop() {
53        return saslQop;
54      }
55  
56      public boolean matches(String stringQop) {
57        if (saslQop.equals(stringQop)) {
58          LOG.warn("Use authentication/integrity/privacy as value for rpc protection "
59              + "configurations instead of auth/auth-int/auth-conf.");
60          return true;
61        }
62        return name().equalsIgnoreCase(stringQop);
63      }
64    }
65  
66    /** Splitting fully qualified Kerberos name into parts */
67    public static String[] splitKerberosName(String fullName) {
68      return fullName.split("[/@]");
69    }
70  
71    static String encodeIdentifier(byte[] identifier) {
72      return new String(Base64.encodeBase64(identifier), StandardCharsets.UTF_8);
73    }
74  
75    static byte[] decodeIdentifier(String identifier) {
76      return Base64.decodeBase64(Bytes.toBytes(identifier));
77    }
78  
79    static char[] encodePassword(byte[] password) {
80      return new String(Base64.encodeBase64(password), StandardCharsets.UTF_8).toCharArray();
81    }
82  
83    /**
84     * Returns {@link org.apache.hadoop.hbase.security.SaslUtil.QualityOfProtection}
85     * corresponding to the given {@code stringQop} value.
86     * @throws IllegalArgumentException If stringQop doesn't match any QOP.
87     */
88    public static QualityOfProtection getQop(String stringQop) {
89      for (QualityOfProtection qop : QualityOfProtection.values()) {
90        if (qop.matches(stringQop)) {
91          return qop;
92        }
93      }
94      throw new IllegalArgumentException("Invalid qop: " +  stringQop
95          + ". It must be one of 'authentication', 'integrity', 'privacy'.");
96    }
97  
98    /**
99     * @param rpcProtection Value of 'hbase.rpc.protection' configuration.
100    * @return Map with values for SASL properties.
101    */
102   public static Map<String, String> initSaslProperties(String rpcProtection) {
103     String saslQop;
104     if (rpcProtection.isEmpty()) {
105       saslQop = QualityOfProtection.AUTHENTICATION.getSaslQop();
106     } else {
107       String[] qops = rpcProtection.split(",");
108       StringBuilder saslQopBuilder = new StringBuilder();
109       for (int i = 0; i < qops.length; ++i) {
110         QualityOfProtection qop = getQop(qops[i]);
111         saslQopBuilder.append(",").append(qop.getSaslQop());
112       }
113       saslQop = saslQopBuilder.substring(1);  // remove first ','
114     }
115     Map<String, String> saslProps = new TreeMap<>();
116     saslProps.put(Sasl.QOP, saslQop);
117     saslProps.put(Sasl.SERVER_AUTH, "true");
118     return saslProps;
119   }
120 
121   static void safeDispose(SaslClient saslClient) {
122     try {
123       saslClient.dispose();
124     } catch (SaslException e) {
125       LOG.error("Error disposing of SASL client", e);
126     }
127   }
128 }