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