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.security.Key;
022import org.apache.hadoop.conf.Configuration;
023import org.apache.hadoop.fs.Path;
024import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
025import org.apache.hadoop.hbase.client.TableDescriptor;
026import org.apache.hadoop.hbase.io.crypto.Cipher;
027import org.apache.hadoop.hbase.io.crypto.Encryption;
028import org.apache.hadoop.hbase.io.hfile.FixedFileTrailer;
029import org.apache.hadoop.hbase.keymeta.ManagedKeyDataCache;
030import org.apache.hadoop.hbase.keymeta.SystemKeyCache;
031import org.apache.yetus.audience.InterfaceAudience;
032import org.apache.yetus.audience.InterfaceStability;
033import org.slf4j.Logger;
034import org.slf4j.LoggerFactory;
035
036/**
037 * Security related generic utility methods.
038 */
039@InterfaceAudience.Private
040@InterfaceStability.Evolving
041public final class SecurityUtil {
042  private static final Logger LOG = LoggerFactory.getLogger(SecurityUtil.class);
043
044  private SecurityUtil() {
045    // Utility class
046  }
047
048  /**
049   * Get the user name from a principal
050   */
051  public static String getUserFromPrincipal(final String principal) {
052    int i = principal.indexOf("/");
053    if (i == -1) {
054      i = principal.indexOf("@");
055    }
056    return (i > -1) ? principal.substring(0, i) : principal;
057  }
058
059  /**
060   * Get the user name from a principal
061   */
062  public static String getPrincipalWithoutRealm(final String principal) {
063    int i = principal.indexOf("@");
064    return (i > -1) ? principal.substring(0, i) : principal;
065  }
066
067  /**
068   * Helper to create an encryption context with current encryption key, suitable for writes. STUB
069   * IMPLEMENTATION - Key management not yet implemented. Cache parameters are placeholders for
070   * future implementation.
071   * @param conf                The current configuration.
072   * @param tableDescriptor     The table descriptor.
073   * @param family              The current column descriptor.
074   * @param managedKeyDataCache The managed key data cache (unused in stub).
075   * @param systemKeyCache      The system key cache (unused in stub).
076   * @return The created encryption context.
077   * @throws IOException           if an encryption key for the column cannot be unwrapped
078   * @throws IllegalStateException in case of encryption related configuration errors
079   */
080  public static Encryption.Context createEncryptionContext(Configuration conf,
081    TableDescriptor tableDescriptor, ColumnFamilyDescriptor family,
082    ManagedKeyDataCache managedKeyDataCache, SystemKeyCache systemKeyCache) throws IOException {
083    Encryption.Context cryptoContext = Encryption.Context.NONE;
084    String cipherName = family.getEncryptionType();
085
086    if (cipherName != null) {
087      if (!Encryption.isEncryptionEnabled(conf)) {
088        throw new IllegalStateException("Encryption for family '" + family.getNameAsString()
089          + "' configured with type '" + cipherName + "' but the encryption feature is disabled");
090      }
091
092      Key key = null;
093      byte[] familyKeyBytes = family.getEncryptionKey();
094
095      // Unwrap family key if present
096      if (familyKeyBytes != null) {
097        key = EncryptionUtil.unwrapKey(conf, familyKeyBytes);
098      }
099
100      Cipher cipher = Encryption.getCipher(conf, cipherName);
101      if (cipher == null) {
102        throw new IllegalStateException("Cipher '" + cipherName + "' is not available");
103      }
104
105      // Generate random key if none provided
106      if (key == null) {
107        key = cipher.getRandomKey();
108      }
109
110      cryptoContext = Encryption.newContext(conf);
111      cryptoContext.setCipher(cipher);
112      cryptoContext.setKey(key);
113    }
114    return cryptoContext;
115  }
116
117  /**
118   * Create an encryption context from encryption key found in a file trailer, suitable for read.
119   * STUB IMPLEMENTATION - Key management not yet implemented. Cache parameters are placeholders for
120   * future implementation.
121   * @param conf                The current configuration.
122   * @param path                The path of the file.
123   * @param trailer             The file trailer.
124   * @param managedKeyDataCache The managed key data cache (unused in stub).
125   * @param systemKeyCache      The system key cache (unused in stub).
126   * @return The created encryption context or null if no key material is available.
127   * @throws IOException if an encryption key for the file cannot be unwrapped
128   */
129  public static Encryption.Context createEncryptionContext(Configuration conf, Path path,
130    FixedFileTrailer trailer, ManagedKeyDataCache managedKeyDataCache,
131    SystemKeyCache systemKeyCache) throws IOException {
132    byte[] keyBytes = trailer.getEncryptionKey();
133    Encryption.Context cryptoContext = Encryption.Context.NONE;
134
135    if (keyBytes != null) {
136      cryptoContext = Encryption.newContext(conf);
137      Key key = EncryptionUtil.unwrapKey(conf, keyBytes);
138      Cipher cipher = Encryption.getCipher(conf, key.getAlgorithm());
139
140      if (cipher == null) {
141        throw new IllegalStateException("Cipher '" + key.getAlgorithm() + "' is not available");
142      }
143
144      cryptoContext.setCipher(cipher);
145      cryptoContext.setKey(key);
146    }
147    return cryptoContext;
148  }
149
150  /**
151   * Check if key management is enabled in configuration. STUB - Always returns false in precursor.
152   * @param conf the configuration to check
153   * @return false in stub implementation
154   */
155  public static boolean isKeyManagementEnabled(Configuration conf) {
156    return false;
157  }
158}