HBASE-21843 RegionGroupingProvider breaks the meta wal file name pattern which may...
[hbase.git] / hbase-server / src / main / java / org / apache / hadoop / hbase / security / HBaseSaslRpcServer.java
blobb3924350b41c37ede2996dcd3ed54cf6756e31b2
1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org.apache.hadoop.hbase.security;
20 import java.io.ByteArrayInputStream;
21 import java.io.DataInputStream;
22 import java.io.IOException;
23 import java.security.PrivilegedExceptionAction;
24 import java.util.Map;
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 import javax.security.sasl.Sasl;
34 import javax.security.sasl.SaslException;
35 import javax.security.sasl.SaslServer;
37 import org.apache.yetus.audience.InterfaceAudience;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40 import org.apache.hadoop.security.UserGroupInformation;
41 import org.apache.hadoop.security.token.SecretManager;
42 import org.apache.hadoop.security.token.SecretManager.InvalidToken;
43 import org.apache.hadoop.security.token.TokenIdentifier;
45 /**
46 * A utility class that encapsulates SASL logic for RPC server. Copied from
47 * <code>org.apache.hadoop.security</code>
49 @InterfaceAudience.Private
50 public class HBaseSaslRpcServer {
52 private static final Logger LOG = LoggerFactory.getLogger(HBaseSaslRpcServer.class);
54 private final SaslServer saslServer;
56 private UserGroupInformation attemptingUser; // user name before auth
58 public HBaseSaslRpcServer(AuthMethod method, Map<String, String> saslProps,
59 SecretManager<TokenIdentifier> secretManager) throws IOException {
60 switch (method) {
61 case DIGEST:
62 if (secretManager == null) {
63 throw new AccessDeniedException("Server is not configured to do DIGEST authentication.");
65 saslServer = Sasl.createSaslServer(AuthMethod.DIGEST.getMechanismName(), null,
66 SaslUtil.SASL_DEFAULT_REALM, saslProps, new SaslDigestCallbackHandler(secretManager));
67 break;
68 case KERBEROS:
69 UserGroupInformation current = UserGroupInformation.getCurrentUser();
70 String fullName = current.getUserName();
71 if (LOG.isDebugEnabled()) {
72 LOG.debug("Kerberos principal name is " + fullName);
74 String[] names = SaslUtil.splitKerberosName(fullName);
75 if (names.length != 3) {
76 throw new AccessDeniedException(
77 "Kerberos principal name does NOT have the expected " + "hostname part: " + fullName);
79 try {
80 saslServer = current.doAs(new PrivilegedExceptionAction<SaslServer>() {
81 @Override
82 public SaslServer run() throws SaslException {
83 return Sasl.createSaslServer(AuthMethod.KERBEROS.getMechanismName(), names[0],
84 names[1], saslProps, new SaslGssCallbackHandler());
86 });
87 } catch (InterruptedException e) {
88 // should not happen
89 throw new AssertionError(e);
91 break;
92 default:
93 throw new IOException("Unknown authentication method " + method);
97 public boolean isComplete() {
98 return saslServer.isComplete();
101 public byte[] evaluateResponse(byte[] response) throws SaslException {
102 return saslServer.evaluateResponse(response);
105 /** Release resources used by wrapped saslServer */
106 public void dispose() {
107 SaslUtil.safeDispose(saslServer);
110 public UserGroupInformation getAttemptingUser() {
111 return attemptingUser;
114 public byte[] wrap(byte[] buf, int off, int len) throws SaslException {
115 return saslServer.wrap(buf, off, len);
118 public byte[] unwrap(byte[] buf, int off, int len) throws SaslException {
119 return saslServer.unwrap(buf, off, len);
122 public String getNegotiatedQop() {
123 return (String) saslServer.getNegotiatedProperty(Sasl.QOP);
126 public String getAuthorizationID() {
127 return saslServer.getAuthorizationID();
130 public static <T extends TokenIdentifier> T getIdentifier(String id,
131 SecretManager<T> secretManager) throws InvalidToken {
132 byte[] tokenId = SaslUtil.decodeIdentifier(id);
133 T tokenIdentifier = secretManager.createIdentifier();
134 try {
135 tokenIdentifier.readFields(new DataInputStream(new ByteArrayInputStream(tokenId)));
136 } catch (IOException e) {
137 throw (InvalidToken) new InvalidToken("Can't de-serialize tokenIdentifier").initCause(e);
139 return tokenIdentifier;
142 /** CallbackHandler for SASL DIGEST-MD5 mechanism */
143 private class SaslDigestCallbackHandler implements CallbackHandler {
144 private SecretManager<TokenIdentifier> secretManager;
146 public SaslDigestCallbackHandler(SecretManager<TokenIdentifier> secretManager) {
147 this.secretManager = secretManager;
150 private char[] getPassword(TokenIdentifier tokenid) throws InvalidToken {
151 return SaslUtil.encodePassword(secretManager.retrievePassword(tokenid));
154 /** {@inheritDoc} */
155 @Override
156 public void handle(Callback[] callbacks) throws InvalidToken, UnsupportedCallbackException {
157 NameCallback nc = null;
158 PasswordCallback pc = null;
159 AuthorizeCallback ac = null;
160 for (Callback callback : callbacks) {
161 if (callback instanceof AuthorizeCallback) {
162 ac = (AuthorizeCallback) callback;
163 } else if (callback instanceof NameCallback) {
164 nc = (NameCallback) callback;
165 } else if (callback instanceof PasswordCallback) {
166 pc = (PasswordCallback) callback;
167 } else if (callback instanceof RealmCallback) {
168 continue; // realm is ignored
169 } else {
170 throw new UnsupportedCallbackException(callback, "Unrecognized SASL DIGEST-MD5 Callback");
173 if (pc != null) {
174 TokenIdentifier tokenIdentifier = getIdentifier(nc.getDefaultName(), secretManager);
175 char[] password = getPassword(tokenIdentifier);
176 UserGroupInformation user = tokenIdentifier.getUser(); // may throw exception
177 attemptingUser = user;
178 if (LOG.isTraceEnabled()) {
179 LOG.trace("SASL server DIGEST-MD5 callback: setting password " + "for client: " +
180 tokenIdentifier.getUser());
182 pc.setPassword(password);
184 if (ac != null) {
185 String authid = ac.getAuthenticationID();
186 String authzid = ac.getAuthorizationID();
187 if (authid.equals(authzid)) {
188 ac.setAuthorized(true);
189 } else {
190 ac.setAuthorized(false);
192 if (ac.isAuthorized()) {
193 if (LOG.isTraceEnabled()) {
194 String username = getIdentifier(authzid, secretManager).getUser().getUserName();
195 LOG.trace(
196 "SASL server DIGEST-MD5 callback: setting " + "canonicalized client ID: " + username);
198 ac.setAuthorizedID(authzid);
204 /** CallbackHandler for SASL GSSAPI Kerberos mechanism */
205 private static class SaslGssCallbackHandler implements CallbackHandler {
207 /** {@inheritDoc} */
208 @Override
209 public void handle(Callback[] callbacks) throws UnsupportedCallbackException {
210 AuthorizeCallback ac = null;
211 for (Callback callback : callbacks) {
212 if (callback instanceof AuthorizeCallback) {
213 ac = (AuthorizeCallback) callback;
214 } else {
215 throw new UnsupportedCallbackException(callback, "Unrecognized SASL GSSAPI Callback");
218 if (ac != null) {
219 String authid = ac.getAuthenticationID();
220 String authzid = ac.getAuthorizationID();
221 if (authid.equals(authzid)) {
222 ac.setAuthorized(true);
223 } else {
224 ac.setAuthorized(false);
226 if (ac.isAuthorized()) {
227 if (LOG.isDebugEnabled()) {
228 LOG.debug(
229 "SASL server GSSAPI callback: setting " + "canonicalized client ID: " + authzid);
231 ac.setAuthorizedID(authzid);