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