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 private final Map<String, String> saslProps; 046 047 public HBaseSaslRpcServer(SaslServerAuthenticationProvider provider, 048 Map<String, String> saslProps, SecretManager<TokenIdentifier> secretManager) 049 throws IOException { 050 serverWithProvider = provider.createServer(secretManager, saslProps); 051 saslServer = serverWithProvider.getServer(); 052 this.saslProps = saslProps; 053 } 054 055 public boolean isComplete() { 056 return saslServer.isComplete(); 057 } 058 059 public byte[] evaluateResponse(byte[] response) throws SaslException { 060 return saslServer.evaluateResponse(response); 061 } 062 063 /** Release resources used by wrapped saslServer */ 064 public void dispose() { 065 SaslUtil.safeDispose(saslServer); 066 } 067 068 public void switchToCryptoAES(CryptoAES cryptoAES) { 069 this.cryptoAES = cryptoAES; 070 } 071 072 public String getAttemptingUser() { 073 return serverWithProvider.getAttemptingUser().map(Object::toString).orElse("Unknown"); 074 } 075 076 public byte[] wrap(byte[] buf, int off, int len) throws SaslException { 077 if (cryptoAES != null) { 078 return cryptoAES.wrap(buf, off, len); 079 } else { 080 return saslServer.wrap(buf, off, len); 081 } 082 } 083 084 public byte[] unwrap(byte[] buf, int off, int len) throws SaslException { 085 if (cryptoAES != null) { 086 return cryptoAES.unwrap(buf, off, len); 087 } else { 088 return saslServer.unwrap(buf, off, len); 089 } 090 } 091 092 public String getNegotiatedQop() { 093 return (String) saslServer.getNegotiatedProperty(Sasl.QOP); 094 } 095 096 public String getRequestedQop() { 097 return (String) saslProps.get(Sasl.QOP); 098 } 099 100 public String getAuthorizationID() { 101 return saslServer.getAuthorizationID(); 102 } 103 104 public static <T extends TokenIdentifier> T getIdentifier(String id, 105 SecretManager<T> secretManager) throws InvalidToken { 106 byte[] tokenId = SaslUtil.decodeIdentifier(id); 107 T tokenIdentifier = secretManager.createIdentifier(); 108 try { 109 tokenIdentifier.readFields(new DataInputStream(new ByteArrayInputStream(tokenId))); 110 } catch (IOException e) { 111 throw (InvalidToken) new InvalidToken("Can't de-serialize tokenIdentifier").initCause(e); 112 } 113 return tokenIdentifier; 114 } 115 116 /** 117 * Unwrap InvalidToken exception, otherwise return the one passed in. 118 */ 119 public static Throwable unwrap(Throwable e) { 120 Throwable cause = e; 121 while (cause != null) { 122 if (cause instanceof InvalidToken) { 123 return cause; 124 } 125 cause = cause.getCause(); 126 } 127 return e; 128 } 129}