1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.security;
19
20 import io.netty.buffer.ByteBuf;
21 import io.netty.channel.ChannelHandlerContext;
22 import io.netty.handler.codec.ByteToMessageDecoder;
23
24 import java.io.IOException;
25 import java.util.List;
26
27 import org.apache.hadoop.hbase.HConstants;
28 import org.apache.hadoop.hbase.classification.InterfaceAudience;
29 import org.apache.hadoop.ipc.RemoteException;
30
31
32
33
34 @InterfaceAudience.Private
35 public class SaslChallengeDecoder extends ByteToMessageDecoder {
36
37 private static final int MAX_CHALLENGE_SIZE = 1024 * 1024;
38
39 private ByteBuf tryDecodeChallenge(ByteBuf in, int offset, int readableBytes) throws IOException {
40 if (readableBytes < 4) {
41 return null;
42 }
43 int len = in.getInt(offset);
44 if (len <= 0) {
45
46 in.readerIndex(offset + 4);
47 return in.retainedSlice(offset, 4);
48 }
49 if (len > MAX_CHALLENGE_SIZE) {
50 throw new IOException(
51 "Sasl challenge too large(" + len + "), max allowed is " + MAX_CHALLENGE_SIZE);
52 }
53 int totalLen = 4 + len;
54 if (readableBytes < totalLen) {
55 return null;
56 }
57 in.readerIndex(offset + totalLen);
58 return in.retainedSlice(offset, totalLen);
59 }
60
61
62 private void tryDecodeError(ByteBuf in, int offset, int readableBytes) throws IOException {
63 if (readableBytes < 4) {
64 return;
65 }
66 int classLen = in.getInt(offset);
67 if (classLen <= 0) {
68 throw new IOException("Invalid exception class name length " + classLen);
69 }
70 if (classLen > MAX_CHALLENGE_SIZE) {
71 throw new IOException("Exception class name length too large(" + classLen +
72 "), max allowed is " + MAX_CHALLENGE_SIZE);
73 }
74 if (readableBytes < 4 + classLen + 4) {
75 return;
76 }
77 int msgLen = in.getInt(offset + 4 + classLen);
78 if (msgLen <= 0) {
79 throw new IOException("Invalid exception message length " + msgLen);
80 }
81 if (msgLen > MAX_CHALLENGE_SIZE) {
82 throw new IOException("Exception message length too large(" + msgLen + "), max allowed is " +
83 MAX_CHALLENGE_SIZE);
84 }
85 int totalLen = classLen + msgLen + 8;
86 if (readableBytes < totalLen) {
87 return;
88 }
89 String className = in.toString(offset + 4, classLen, HConstants.UTF8_CHARSET);
90 String msg = in.toString(offset + classLen + 8, msgLen, HConstants.UTF8_CHARSET);
91 in.readerIndex(offset + totalLen);
92 throw new RemoteException(className, msg);
93 }
94
95 @Override
96 protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
97 int readableBytes = in.readableBytes();
98 if (readableBytes < 4) {
99 return;
100 }
101 int offset = in.readerIndex();
102 int status = in.getInt(offset);
103 if (status == SaslStatus.SUCCESS.state) {
104 ByteBuf challenge = tryDecodeChallenge(in, offset + 4, readableBytes - 4);
105 if (challenge != null) {
106 out.add(challenge);
107 }
108 } else {
109 tryDecodeError(in, offset + 4, readableBytes - 4);
110 }
111 }
112 }