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.BufferedInputStream;
22 import java.io.BufferedOutputStream;
23 import java.io.DataInputStream;
24 import java.io.DataOutputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.OutputStream;
28
29 import javax.security.sasl.Sasl;
30 import javax.security.sasl.SaslException;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.apache.hadoop.hbase.classification.InterfaceAudience;
35 import org.apache.hadoop.io.WritableUtils;
36 import org.apache.hadoop.ipc.RemoteException;
37 import org.apache.hadoop.security.SaslInputStream;
38 import org.apache.hadoop.security.SaslOutputStream;
39 import org.apache.hadoop.security.token.Token;
40 import org.apache.hadoop.security.token.TokenIdentifier;
41
42
43
44
45
46 @InterfaceAudience.Private
47 public class HBaseSaslRpcClient extends AbstractHBaseSaslRpcClient {
48
49 private static final Log LOG = LogFactory.getLog(HBaseSaslRpcClient.class);
50
51 public HBaseSaslRpcClient(AuthMethod method, Token<? extends TokenIdentifier> token,
52 String serverPrincipal, boolean fallbackAllowed) throws IOException {
53 super(method, token, serverPrincipal, fallbackAllowed);
54 }
55
56 public HBaseSaslRpcClient(AuthMethod method, Token<? extends TokenIdentifier> token,
57 String serverPrincipal, boolean fallbackAllowed, String rpcProtection) throws IOException {
58 super(method, token, serverPrincipal, fallbackAllowed, rpcProtection);
59 }
60
61 private static void readStatus(DataInputStream inStream) throws IOException {
62 int status = inStream.readInt();
63 if (status != SaslStatus.SUCCESS.state) {
64 throw new RemoteException(WritableUtils.readString(inStream),
65 WritableUtils.readString(inStream));
66 }
67 }
68
69
70
71
72
73
74
75
76 public boolean saslConnect(InputStream inS, OutputStream outS) throws IOException {
77 DataInputStream inStream = new DataInputStream(new BufferedInputStream(inS));
78 DataOutputStream outStream = new DataOutputStream(new BufferedOutputStream(outS));
79
80 try {
81 byte[] saslToken = getInitialResponse();
82 if (saslToken != null) {
83 outStream.writeInt(saslToken.length);
84 outStream.write(saslToken, 0, saslToken.length);
85 outStream.flush();
86 if (LOG.isDebugEnabled()) {
87 LOG.debug("Have sent token of size " + saslToken.length + " from initSASLContext.");
88 }
89 }
90 if (!isComplete()) {
91 readStatus(inStream);
92 int len = inStream.readInt();
93 if (len == SaslUtil.SWITCH_TO_SIMPLE_AUTH) {
94 if (!fallbackAllowed) {
95 throw new IOException("Server asks us to fall back to SIMPLE auth, "
96 + "but this client is configured to only allow secure connections.");
97 }
98 if (LOG.isDebugEnabled()) {
99 LOG.debug("Server asks us to fall back to simple auth.");
100 }
101 dispose();
102 return false;
103 }
104 saslToken = new byte[len];
105 if (LOG.isDebugEnabled()) {
106 LOG.debug("Will read input token of size " + saslToken.length
107 + " for processing by initSASLContext");
108 }
109 inStream.readFully(saslToken);
110 }
111
112 while (!isComplete()) {
113 saslToken = evaluateChallenge(saslToken);
114 if (saslToken != null) {
115 if (LOG.isDebugEnabled()) {
116 LOG.debug("Will send token of size " + saslToken.length + " from initSASLContext.");
117 }
118 outStream.writeInt(saslToken.length);
119 outStream.write(saslToken, 0, saslToken.length);
120 outStream.flush();
121 }
122 if (!isComplete()) {
123 readStatus(inStream);
124 saslToken = new byte[inStream.readInt()];
125 if (LOG.isDebugEnabled()) {
126 LOG.debug("Will read input token of size " + saslToken.length
127 + " for processing by initSASLContext");
128 }
129 inStream.readFully(saslToken);
130 }
131 }
132 if (LOG.isDebugEnabled()) {
133 LOG.debug("SASL client context established. Negotiated QoP: "
134 + saslClient.getNegotiatedProperty(Sasl.QOP));
135 }
136 return true;
137 } catch (IOException e) {
138 try {
139 saslClient.dispose();
140 } catch (SaslException ignored) {
141
142 }
143 throw e;
144 }
145 }
146
147
148
149
150
151
152
153 public InputStream getInputStream(InputStream in) throws IOException {
154 if (!saslClient.isComplete()) {
155 throw new IOException("Sasl authentication exchange hasn't completed yet");
156 }
157 return new SaslInputStream(in, saslClient);
158 }
159
160
161
162
163
164
165
166 public OutputStream getOutputStream(OutputStream out) throws IOException {
167 if (!saslClient.isComplete()) {
168 throw new IOException("Sasl authentication exchange hasn't completed yet");
169 }
170 return new SaslOutputStream(out, saslClient);
171 }
172 }