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.util.Map;
22  import java.util.TreeMap;
23  
24  import javax.security.sasl.Sasl;
25  import javax.security.sasl.SaslClient;
26  import javax.security.sasl.SaslException;
27
28  import org.apache.commons.codec.binary.Base64;
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.hadoop.hbase.classification.InterfaceAudience;
32
33  @InterfaceAudience.Private
34  public class SaslUtil {
35    private static final Log LOG = LogFactory.getLog(SaslUtil.class);
36    public static final String SASL_DEFAULT_REALM = "default";
37    public static final int SWITCH_TO_SIMPLE_AUTH = -88;
38
39    public enum QualityOfProtection {
40      AUTHENTICATION("auth"),
41      INTEGRITY("auth-int"),
42      PRIVACY("auth-conf");
43  
44      private final String saslQop;
45
46      QualityOfProtection(String saslQop) {
47        this.saslQop = saslQop;
48      }
49
50      public String getSaslQop() {
51        return saslQop;
52      }
53
54      public boolean matches(String stringQop) {
55        if (saslQop.equals(stringQop)) {
56          LOG.warn("Use authentication/integrity/privacy as value for rpc protection "
57              + "configurations instead of auth/auth-int/auth-conf.");
58          return true;
59        }
60        return name().equalsIgnoreCase(stringQop);
61      }
62    }
63
64    /** Splitting fully qualified Kerberos name into parts */
65    public static String[] splitKerberosName(String fullName) {
66      return fullName.split("[/@]");
67    }
68
69    static String encodeIdentifier(byte[] identifier) {
70      return new String(Base64.encodeBase64(identifier));
71    }
72
73    static byte[] decodeIdentifier(String identifier) {
74      return Base64.decodeBase64(identifier.getBytes());
75    }
76
77    static char[] encodePassword(byte[] password) {
78      return new String(Base64.encodeBase64(password)).toCharArray();
79    }
80
81    /**
82     * Returns {@link org.apache.hadoop.hbase.security.SaslUtil.QualityOfProtection}
83     * corresponding to the given {@code stringQop} value.
84     * @throws IllegalArgumentException If stringQop doesn't match any QOP.
85     */
86    public static QualityOfProtection getQop(String stringQop) {
87      for (QualityOfProtection qop : QualityOfProtection.values()) {
88        if (qop.matches(stringQop)) {
89          return qop;
90        }
91      }
92      throw new IllegalArgumentException("Invalid qop: " +  stringQop
93          + ". It must be one of 'authentication', 'integrity', 'privacy'.");
94    }
95
96    /**
97     * @param rpcProtection Value of 'hbase.rpc.protection' configuration.
98     * @return Map with values for SASL properties.
99     */
100   static Map<String, String> initSaslProperties(String rpcProtection) {
101     String saslQop;
102     if (rpcProtection.isEmpty()) {
103       saslQop = QualityOfProtection.AUTHENTICATION.getSaslQop();
104     } else {
105       String[] qops = rpcProtection.split(",");
106       StringBuilder saslQopBuilder = new StringBuilder();
107       for (int i = 0; i < qops.length; ++i) {
108         QualityOfProtection qop = getQop(qops[i]);
109         saslQopBuilder.append(",").append(qop.getSaslQop());
110       }
111       saslQop = saslQopBuilder.substring(1);  // remove first ','
112     }
113     Map<String, String> saslProps = new TreeMap<>();
114     saslProps.put(Sasl.QOP, saslQop);
115     saslProps.put(Sasl.SERVER_AUTH, "true");
116     return saslProps;
117   }
118
119   static void safeDispose(SaslClient saslClient) {
120     try {
121       saslClient.dispose();
122     } catch (SaslException e) {
123       LOG.error("Error disposing of SASL client", e);
124     }
125   }
126 }