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.ByteArrayInputStream; 021import java.io.DataInputStream; 022import java.io.IOException; 023import java.util.Map; 024import javax.security.sasl.Sasl; 025import javax.security.sasl.SaslException; 026import javax.security.sasl.SaslServer; 027import org.apache.hadoop.hbase.io.crypto.aes.CryptoAES; 028import org.apache.hadoop.hbase.security.provider.AttemptingUserProvidingSaslServer; 029import org.apache.hadoop.hbase.security.provider.SaslServerAuthenticationProvider; 030import org.apache.hadoop.security.token.SecretManager; 031import org.apache.hadoop.security.token.SecretManager.InvalidToken; 032import org.apache.hadoop.security.token.TokenIdentifier; 033import org.apache.yetus.audience.InterfaceAudience; 034 035/** 036 * A utility class that encapsulates SASL logic for RPC server. Copied from 037 * <code>org.apache.hadoop.security</code> 038 */ 039@InterfaceAudience.Private 040public class HBaseSaslRpcServer { 041 042 private final AttemptingUserProvidingSaslServer serverWithProvider; 043 private final SaslServer saslServer; 044 private CryptoAES cryptoAES; 045 046 public HBaseSaslRpcServer(SaslServerAuthenticationProvider provider, 047 Map<String, String> saslProps, SecretManager<TokenIdentifier> secretManager) 048 throws IOException { 049 serverWithProvider = provider.createServer(secretManager, saslProps); 050 saslServer = serverWithProvider.getServer(); 051 } 052 053 public boolean isComplete() { 054 return saslServer.isComplete(); 055 } 056 057 public byte[] evaluateResponse(byte[] response) throws SaslException { 058 return saslServer.evaluateResponse(response); 059 } 060 061 /** Release resources used by wrapped saslServer */ 062 public void dispose() { 063 SaslUtil.safeDispose(saslServer); 064 } 065 066 public void switchToCryptoAES(CryptoAES cryptoAES) { 067 this.cryptoAES = cryptoAES; 068 } 069 070 public String getAttemptingUser() { 071 return serverWithProvider.getAttemptingUser().map(Object::toString).orElse("Unknown"); 072 } 073 074 public byte[] wrap(byte[] buf, int off, int len) throws SaslException { 075 if (cryptoAES != null) { 076 return cryptoAES.wrap(buf, off, len); 077 } else { 078 return saslServer.wrap(buf, off, len); 079 } 080 } 081 082 public byte[] unwrap(byte[] buf, int off, int len) throws SaslException { 083 if (cryptoAES != null) { 084 return cryptoAES.unwrap(buf, off, len); 085 } else { 086 return saslServer.unwrap(buf, off, len); 087 } 088 } 089 090 public String getNegotiatedQop() { 091 return (String) saslServer.getNegotiatedProperty(Sasl.QOP); 092 } 093 094 public String getAuthorizationID() { 095 return saslServer.getAuthorizationID(); 096 } 097 098 public static <T extends TokenIdentifier> T getIdentifier(String id, 099 SecretManager<T> secretManager) throws InvalidToken { 100 byte[] tokenId = SaslUtil.decodeIdentifier(id); 101 T tokenIdentifier = secretManager.createIdentifier(); 102 try { 103 tokenIdentifier.readFields(new DataInputStream(new ByteArrayInputStream(tokenId))); 104 } catch (IOException e) { 105 throw (InvalidToken) new InvalidToken("Can't de-serialize tokenIdentifier").initCause(e); 106 } 107 return tokenIdentifier; 108 } 109 110 /** 111 * Unwrap InvalidToken exception, otherwise return the one passed in. 112 */ 113 public static Throwable unwrap(Throwable e) { 114 Throwable cause = e; 115 while (cause != null) { 116 if (cause instanceof InvalidToken) { 117 return cause; 118 } 119 cause = cause.getCause(); 120 } 121 return e; 122 } 123}