1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
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
85
86
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
100
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);
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 }