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.io.ByteArrayInputStream;
22 import java.io.DataInputStream;
23 import java.io.IOException;
24 import java.util.Locale;
25 import java.util.Map;
26
27 import javax.security.auth.callback.Callback;
28 import javax.security.auth.callback.CallbackHandler;
29 import javax.security.auth.callback.NameCallback;
30 import javax.security.auth.callback.PasswordCallback;
31 import javax.security.auth.callback.UnsupportedCallbackException;
32 import javax.security.sasl.AuthorizeCallback;
33 import javax.security.sasl.RealmCallback;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37 import org.apache.hadoop.conf.Configuration;
38 import org.apache.hadoop.hbase.classification.InterfaceAudience;
39 import org.apache.hadoop.hbase.ipc.RpcServer;
40 import org.apache.hadoop.hbase.security.SaslUtil.QualityOfProtection;
41 import org.apache.hadoop.security.UserGroupInformation;
42 import org.apache.hadoop.security.token.SecretManager;
43 import org.apache.hadoop.security.token.SecretManager.InvalidToken;
44 import org.apache.hadoop.security.token.TokenIdentifier;
45
46
47
48
49 @InterfaceAudience.Private
50 public class HBaseSaslRpcServer {
51 private static final Log LOG = LogFactory.getLog(HBaseSaslRpcServer.class);
52
53 private static Map<String, String> saslProps = null;
54
55 public static void init(Configuration conf) {
56 saslProps = SaslUtil.initSaslProperties(conf.get("hbase.rpc.protection",
57 QualityOfProtection.AUTHENTICATION.name().toLowerCase(Locale.ROOT)));
58 }
59
60 public static Map<String, String> getSaslProps() {
61 return saslProps;
62 }
63
64 public static <T extends TokenIdentifier> T getIdentifier(String id,
65 SecretManager<T> secretManager) throws InvalidToken {
66 byte[] tokenId = SaslUtil.decodeIdentifier(id);
67 T tokenIdentifier = secretManager.createIdentifier();
68 try {
69 tokenIdentifier.readFields(new DataInputStream(new ByteArrayInputStream(
70 tokenId)));
71 } catch (IOException e) {
72 throw (InvalidToken) new InvalidToken(
73 "Can't de-serialize tokenIdentifier").initCause(e);
74 }
75 return tokenIdentifier;
76 }
77
78
79
80 public static class SaslDigestCallbackHandler implements CallbackHandler {
81 private SecretManager<TokenIdentifier> secretManager;
82 private RpcServer.Connection connection;
83
84 public SaslDigestCallbackHandler(
85 SecretManager<TokenIdentifier> secretManager,
86 RpcServer.Connection connection) {
87 this.secretManager = secretManager;
88 this.connection = connection;
89 }
90
91 private char[] getPassword(TokenIdentifier tokenid) throws InvalidToken {
92 return SaslUtil.encodePassword(secretManager.retrievePassword(tokenid));
93 }
94
95
96 @Override
97 public void handle(Callback[] callbacks) throws InvalidToken,
98 UnsupportedCallbackException {
99 NameCallback nc = null;
100 PasswordCallback pc = null;
101 AuthorizeCallback ac = null;
102 for (Callback callback : callbacks) {
103 if (callback instanceof AuthorizeCallback) {
104 ac = (AuthorizeCallback) callback;
105 } else if (callback instanceof NameCallback) {
106 nc = (NameCallback) callback;
107 } else if (callback instanceof PasswordCallback) {
108 pc = (PasswordCallback) callback;
109 } else if (callback instanceof RealmCallback) {
110 continue;
111 } else {
112 throw new UnsupportedCallbackException(callback,
113 "Unrecognized SASL DIGEST-MD5 Callback");
114 }
115 }
116 if (pc != null) {
117 TokenIdentifier tokenIdentifier = getIdentifier(nc.getDefaultName(), secretManager);
118 char[] password = getPassword(tokenIdentifier);
119 UserGroupInformation user = null;
120 user = tokenIdentifier.getUser();
121 connection.attemptingUser = user;
122 if (LOG.isTraceEnabled()) {
123 LOG.trace("SASL server DIGEST-MD5 callback: setting password "
124 + "for client: " + tokenIdentifier.getUser());
125 }
126 pc.setPassword(password);
127 }
128 if (ac != null) {
129 String authid = ac.getAuthenticationID();
130 String authzid = ac.getAuthorizationID();
131 if (authid.equals(authzid)) {
132 ac.setAuthorized(true);
133 } else {
134 ac.setAuthorized(false);
135 }
136 if (ac.isAuthorized()) {
137 if (LOG.isTraceEnabled()) {
138 String username =
139 getIdentifier(authzid, secretManager).getUser().getUserName();
140 LOG.trace("SASL server DIGEST-MD5 callback: setting "
141 + "canonicalized client ID: " + username);
142 }
143 ac.setAuthorizedID(authzid);
144 }
145 }
146 }
147 }
148
149
150 public static class SaslGssCallbackHandler implements CallbackHandler {
151
152
153 @Override
154 public void handle(Callback[] callbacks) throws
155 UnsupportedCallbackException {
156 AuthorizeCallback ac = null;
157 for (Callback callback : callbacks) {
158 if (callback instanceof AuthorizeCallback) {
159 ac = (AuthorizeCallback) callback;
160 } else {
161 throw new UnsupportedCallbackException(callback,
162 "Unrecognized SASL GSSAPI Callback");
163 }
164 }
165 if (ac != null) {
166 String authid = ac.getAuthenticationID();
167 String authzid = ac.getAuthorizationID();
168 if (authid.equals(authzid)) {
169 ac.setAuthorized(true);
170 } else {
171 ac.setAuthorized(false);
172 }
173 if (ac.isAuthorized()) {
174 if (LOG.isDebugEnabled())
175 LOG.debug("SASL server GSSAPI callback: setting "
176 + "canonicalized client ID: " + authzid);
177 ac.setAuthorizedID(authzid);
178 }
179 }
180 }
181 }
182 }