001/** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019package org.apache.hadoop.hbase.security; 020 021import java.util.Base64; 022import java.util.Map; 023import java.util.TreeMap; 024 025import javax.security.sasl.Sasl; 026import javax.security.sasl.SaslClient; 027import javax.security.sasl.SaslException; 028import javax.security.sasl.SaslServer; 029 030import org.apache.hadoop.hbase.util.Bytes; 031import org.apache.yetus.audience.InterfaceAudience; 032import org.slf4j.Logger; 033import org.slf4j.LoggerFactory; 034 035@InterfaceAudience.Private 036public class SaslUtil { 037 private static final Logger LOG = LoggerFactory.getLogger(SaslUtil.class); 038 public static final String SASL_DEFAULT_REALM = "default"; 039 public static final int SWITCH_TO_SIMPLE_AUTH = -88; 040 041 public enum QualityOfProtection { 042 AUTHENTICATION("auth"), 043 INTEGRITY("auth-int"), 044 PRIVACY("auth-conf"); 045 046 private final String saslQop; 047 048 QualityOfProtection(String saslQop) { 049 this.saslQop = saslQop; 050 } 051 052 public String getSaslQop() { 053 return saslQop; 054 } 055 056 public boolean matches(String stringQop) { 057 if (saslQop.equals(stringQop)) { 058 LOG.warn("Use authentication/integrity/privacy as value for rpc protection " 059 + "configurations instead of auth/auth-int/auth-conf."); 060 return true; 061 } 062 return name().equalsIgnoreCase(stringQop); 063 } 064 } 065 066 /** Splitting fully qualified Kerberos name into parts */ 067 public static String[] splitKerberosName(String fullName) { 068 return fullName.split("[/@]"); 069 } 070 071 public static String encodeIdentifier(byte[] identifier) { 072 return Base64.getEncoder().encodeToString(identifier); 073 } 074 075 public static byte[] decodeIdentifier(String identifier) { 076 return Base64.getDecoder().decode(Bytes.toBytes(identifier)); 077 } 078 079 public static char[] encodePassword(byte[] password) { 080 return Base64.getEncoder().encodeToString(password).toCharArray(); 081 } 082 083 /** 084 * Returns {@link org.apache.hadoop.hbase.security.SaslUtil.QualityOfProtection} 085 * corresponding to the given {@code stringQop} value. 086 * @throws IllegalArgumentException If stringQop doesn't match any QOP. 087 */ 088 public static QualityOfProtection getQop(String stringQop) { 089 for (QualityOfProtection qop : QualityOfProtection.values()) { 090 if (qop.matches(stringQop)) { 091 return qop; 092 } 093 } 094 throw new IllegalArgumentException("Invalid qop: " + stringQop 095 + ". It must be one of 'authentication', 'integrity', 'privacy'."); 096 } 097 098 /** 099 * @param rpcProtection Value of 'hbase.rpc.protection' configuration. 100 * @return Map with values for SASL properties. 101 */ 102 public static Map<String, String> initSaslProperties(String rpcProtection) { 103 String saslQop; 104 if (rpcProtection.isEmpty()) { 105 saslQop = QualityOfProtection.AUTHENTICATION.getSaslQop(); 106 } else { 107 String[] qops = rpcProtection.split(","); 108 StringBuilder saslQopBuilder = new StringBuilder(); 109 for (int i = 0; i < qops.length; ++i) { 110 QualityOfProtection qop = getQop(qops[i]); 111 saslQopBuilder.append(",").append(qop.getSaslQop()); 112 } 113 saslQop = saslQopBuilder.substring(1); // remove first ',' 114 } 115 Map<String, String> saslProps = new TreeMap<>(); 116 saslProps.put(Sasl.QOP, saslQop); 117 saslProps.put(Sasl.SERVER_AUTH, "true"); 118 return saslProps; 119 } 120 121 static void safeDispose(SaslClient saslClient) { 122 try { 123 saslClient.dispose(); 124 } catch (SaslException e) { 125 LOG.error("Error disposing of SASL client", e); 126 } 127 } 128 129 static void safeDispose(SaslServer saslServer) { 130 try { 131 saslServer.dispose(); 132 } catch (SaslException e) { 133 LOG.error("Error disposing of SASL server", e); 134 } 135 } 136}