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