001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.security; 019 020import java.io.IOException; 021import java.net.InetAddress; 022import java.util.Map; 023import javax.security.sasl.Sasl; 024import javax.security.sasl.SaslClient; 025import javax.security.sasl.SaslException; 026import org.apache.hadoop.conf.Configuration; 027import org.apache.hadoop.hbase.security.provider.SaslClientAuthenticationProvider; 028import org.apache.hadoop.security.token.Token; 029import org.apache.hadoop.security.token.TokenIdentifier; 030import org.apache.yetus.audience.InterfaceAudience; 031 032/** 033 * A utility class that encapsulates SASL logic for RPC client. Copied from 034 * <code>org.apache.hadoop.security</code> 035 * @since 2.0.0 036 */ 037@InterfaceAudience.Private 038public abstract class AbstractHBaseSaslRpcClient { 039 private static final byte[] EMPTY_TOKEN = new byte[0]; 040 041 protected final SaslClient saslClient; 042 043 protected final boolean fallbackAllowed; 044 045 protected final Map<String, String> saslProps; 046 047 /** 048 * Create a HBaseSaslRpcClient for an authentication method 049 * @param conf the configuration object 050 * @param provider the authentication provider 051 * @param token token to use if needed by the authentication method 052 * @param serverAddr the address of the hbase service 053 * @param servicePrincipal the service principal to use if needed by the authentication method 054 * @param fallbackAllowed does the client allow fallback to simple authentication 055 */ 056 protected AbstractHBaseSaslRpcClient(Configuration conf, 057 SaslClientAuthenticationProvider provider, Token<? extends TokenIdentifier> token, 058 InetAddress serverAddr, String servicePrincipal, boolean fallbackAllowed) throws IOException { 059 this(conf, provider, token, serverAddr, servicePrincipal, fallbackAllowed, "authentication"); 060 } 061 062 /** 063 * Create a HBaseSaslRpcClient for an authentication method 064 * @param conf configuration object 065 * @param provider the authentication provider 066 * @param token token to use if needed by the authentication method 067 * @param serverAddr the address of the hbase service 068 * @param servicePrincipal the service principal to use if needed by the authentication method 069 * @param fallbackAllowed does the client allow fallback to simple authentication 070 * @param rpcProtection the protection level ("authentication", "integrity" or "privacy") 071 */ 072 protected AbstractHBaseSaslRpcClient(Configuration conf, 073 SaslClientAuthenticationProvider provider, Token<? extends TokenIdentifier> token, 074 InetAddress serverAddr, String servicePrincipal, boolean fallbackAllowed, String rpcProtection) 075 throws IOException { 076 this.fallbackAllowed = fallbackAllowed; 077 saslProps = SaslUtil.initSaslProperties(rpcProtection); 078 079 saslClient = 080 provider.createClient(conf, serverAddr, servicePrincipal, token, fallbackAllowed, saslProps); 081 if (saslClient == null) { 082 throw new IOException( 083 "Authentication provider " + provider.getClass() + " returned a null SaslClient"); 084 } 085 } 086 087 /** 088 * Computes the initial response a client sends to a server to begin the SASL challenge/response 089 * handshake. If the client's SASL mechanism does not have an initial response, an empty token 090 * will be returned without querying the evaluateChallenge method, as an authentication processing 091 * must be started by client. 092 * @return The client's initial response to send the server (which may be empty). 093 */ 094 public byte[] getInitialResponse() throws SaslException { 095 if (saslClient.hasInitialResponse()) { 096 return saslClient.evaluateChallenge(EMPTY_TOKEN); 097 } 098 return EMPTY_TOKEN; 099 } 100 101 public boolean isComplete() { 102 return saslClient.isComplete(); 103 } 104 105 public byte[] evaluateChallenge(byte[] challenge) throws SaslException { 106 return saslClient.evaluateChallenge(challenge); 107 } 108 109 /** 110 * Check that SASL has successfully negotiated a QOP according to the requested rpcProtection 111 * @throws IOException if the negotiated QOP is insufficient 112 */ 113 protected void verifyNegotiatedQop() throws IOException { 114 SaslUtil.verifyNegotiatedQop(saslProps.get(Sasl.QOP), 115 (String) saslClient.getNegotiatedProperty(Sasl.QOP)); 116 } 117 118 /** Release resources used by wrapped saslClient */ 119 public void dispose() { 120 SaslUtil.safeDispose(saslClient); 121 } 122}