Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ambari.server.serveraction.kerberos; import org.apache.ambari.server.utils.ShellCommandUtil; import org.apache.commons.codec.binary.Base64; import org.apache.directory.server.kerberos.shared.crypto.encryption.KerberosKeyFactory; import org.apache.directory.server.kerberos.shared.keytab.Keytab; import org.apache.directory.server.kerberos.shared.keytab.KeytabEntry; import org.apache.directory.shared.kerberos.KerberosTime; import org.apache.directory.shared.kerberos.codec.types.EncryptionType; import org.apache.directory.shared.kerberos.components.EncryptionKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.security.SecureRandom; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * KerberosOperationHandler is an abstract class providing basic implementations of common Kerberos * operations (like generating secure passwords) and placeholders for KDC-specific operations * (such as creating principals). */ public abstract class KerberosOperationHandler { private final static Logger LOG = LoggerFactory.getLogger(KerberosOperationHandler.class); private final static SecureRandom SECURE_RANDOM = new SecureRandom(); /** * The number of characters to generate for a secure password */ protected final static int SECURE_PASSWORD_LENGTH = 18; /** * Kerberos-env configuration property name: ldap_url */ public final static String KERBEROS_ENV_LDAP_URL = "ldap_url"; /** * Kerberos-env configuration property name: container_dn */ public final static String KERBEROS_ENV_PRINCIPAL_CONTAINER_DN = "container_dn"; /** * Kerberos-env configuration property name: create_attributes_template */ public final static String KERBEROS_ENV_CREATE_ATTRIBUTES_TEMPLATE = "create_attributes_template"; /** * Kerberos-env configuration property name: encryption_types */ public final static String KERBEROS_ENV_ENCRYPTION_TYPES = "encryption_types"; /** * Kerberos-env configuration property name: kdc_host */ public final static String KERBEROS_ENV_KDC_HOST = "kdc_host"; /** * Kerberos-env configuration property name: admin_server_host */ public final static String KERBEROS_ENV_ADMIN_SERVER_HOST = "admin_server_host"; /** * The set of available characters to use when generating a secure password */ private final static char[] SECURE_PASSWORD_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890?.!$%^*()-_+=~" .toCharArray(); /** * A Map of MIT KDC Encryption types to EncryptionType values. * <p/> * See http://web.mit.edu/kerberos/krb5-devel/doc/admin/conf_files/kdc_conf.html#encryption-types */ private static final Map<String, Set<EncryptionType>> ENCRYPTION_TYPE_TRANSLATION_MAP = Collections .unmodifiableMap(new HashMap<String, Set<EncryptionType>>() { { // aes: The AES family: aes256-cts-hmac-sha1-96 and aes128-cts-hmac-sha1-96 put("aes", EnumSet.of(EncryptionType.AES256_CTS_HMAC_SHA1_96, EncryptionType.AES128_CTS_HMAC_SHA1_96)); // aes256-cts-hmac-sha1-96 aes256-cts: AES-256 CTS mode with 96-bit SHA-1 HMAC put("aes256-cts-hmac-sha1-96", EnumSet.of(EncryptionType.AES256_CTS_HMAC_SHA1_96)); put("aes256-cts", EnumSet.of(EncryptionType.AES256_CTS_HMAC_SHA1_96)); put("aes-256", EnumSet.of(EncryptionType.AES256_CTS_HMAC_SHA1_96)); // aes128-cts-hmac-sha1-96 aes128-cts AES-128: CTS mode with 96-bit SHA-1 HMAC put("aes128-cts-hmac-sha1-96", EnumSet.of(EncryptionType.AES128_CTS_HMAC_SHA1_96)); put("aes128-cts", EnumSet.of(EncryptionType.AES128_CTS_HMAC_SHA1_96)); put("aes-128", EnumSet.of(EncryptionType.AES128_CTS_HMAC_SHA1_96)); // rc4 The RC4 family: arcfour-hmac put("rc4", EnumSet.of(EncryptionType.RC4_HMAC)); // arcfour-hmac rc4-hmac arcfour-hmac-md5: RC4 with HMAC/MD5 put("arcfour-hmac", EnumSet.of(EncryptionType.RC4_HMAC)); put("rc4-hmac", EnumSet.of(EncryptionType.RC4_HMAC)); put("arcfour-hmac-md5", EnumSet.of(EncryptionType.UNKNOWN)); // arcfour-hmac-exp rc4-hmac-exp arcfour-hmac-md5-exp: Exportable RC4 with HMAC/MD5 (weak) put("arcfour-hmac-exp", EnumSet.of(EncryptionType.RC4_HMAC_EXP)); put("rc4-hmac-exp", EnumSet.of(EncryptionType.RC4_HMAC_EXP)); put("arcfour-hmac-md5-exp", EnumSet.of(EncryptionType.UNKNOWN)); // camellia The Camellia family: camellia256-cts-cmac and camellia128-cts-cmac put("camellia", EnumSet.of(EncryptionType.UNKNOWN)); // camellia256-cts-cmac camellia256-cts: Camellia-256 CTS mode with CMAC put("camellia256-cts-cmac", EnumSet.of(EncryptionType.UNKNOWN)); put("camellia256-cts", EnumSet.of(EncryptionType.UNKNOWN)); // camellia128-cts-cmac camellia128-cts: Camellia-128 CTS mode with CMAC put("camellia128-cts-cmac", EnumSet.of(EncryptionType.UNKNOWN)); put("camellia128-cts", EnumSet.of(EncryptionType.UNKNOWN)); //des: The DES family: des-cbc-crc, des-cbc-md5, and des-cbc-md4 (weak) put("des", EnumSet.of(EncryptionType.DES_CBC_CRC, EncryptionType.DES_CBC_MD5, EncryptionType.DES_CBC_MD4)); // des-cbc-md4: DES cbc mode with RSA-MD4 (weak) put("des-cbc-md4", EnumSet.of(EncryptionType.DES_CBC_MD4)); // des-cbc-md5: DES cbc mode with RSA-MD5 (weak) put("des-cbc-md5", EnumSet.of(EncryptionType.DES_CBC_MD5)); // des-cbc-crc: DES cbc mode with CRC-32 (weak) put("des-cbc-crc", EnumSet.of(EncryptionType.DES_CBC_CRC)); // des-cbc-raw: DES cbc mode raw (weak) put("des-cbc-raw", EnumSet.of(EncryptionType.UNKNOWN)); // des-hmac-sha1: DES with HMAC/sha1 (weak) put("des-hmac-sha1", EnumSet.of(EncryptionType.UNKNOWN)); // des3: The triple DES family: des3-cbc-sha1 put("des3", EnumSet.of(EncryptionType.DES3_CBC_SHA1_KD)); // Using DES3_CBC_SHA1_KD since DES3_CBC_SHA1 invalid key issues with KDC // des3-cbc-raw: Triple DES cbc mode raw (weak) put("des3-cbc-raw", EnumSet.of(EncryptionType.UNKNOWN)); // des3-cbc-sha1 des3-hmac-sha1 des3-cbc-sha1-kd: Triple DES cbc mode with HMAC/sha1 put("des3-cbc-sha1", EnumSet.of(EncryptionType.DES3_CBC_SHA1_KD)); // Using DES3_CBC_SHA1_KD since DES3_CBC_SHA1 invalid key issues with KDC put("des3-hmac-sha1", EnumSet.of(EncryptionType.UNKNOWN)); put("des3-cbc-sha1-kd", EnumSet.of(EncryptionType.DES3_CBC_SHA1_KD)); } }); /** * The default set of ciphers to use for creating keytab entries */ private static final Set<EncryptionType> DEFAULT_CIPHERS = Collections .unmodifiableSet(new HashSet<EncryptionType>() { { add(EncryptionType.DES_CBC_MD5); add(EncryptionType.DES3_CBC_SHA1_KD); add(EncryptionType.RC4_HMAC); add(EncryptionType.AES128_CTS_HMAC_SHA1_96); add(EncryptionType.AES256_CTS_HMAC_SHA1_96); } }); private KerberosCredential administratorCredentials = null; private String defaultRealm = null; private Set<EncryptionType> keyEncryptionTypes = new HashSet<EncryptionType>(DEFAULT_CIPHERS); private boolean open = false; /** * Create a secure (random) password using a secure random number generator and a set of (reasonable) * characters. * * @return a String containing the new password */ public String createSecurePassword() { return createSecurePassword(SECURE_PASSWORD_LENGTH); } /** * Create a secure (random) password using a secure random number generator and a set of (reasonable) * characters. * * @param length an integer value declaring the length of the password to create, * if <1, a default will be used. * @return a String containing the new password */ public String createSecurePassword(int length) { StringBuilder passwordBuilder; // If the supplied length is less than 1 use the default value. if (length < 1) { length = SECURE_PASSWORD_LENGTH; } // Create a new StringBuilder and ensure its capacity is set for the length of the password to // be generated passwordBuilder = new StringBuilder(length); // For each character to be added to the password, (securely) generate a random number to pull // a random character from the character array for (int i = 0; i < length; i++) { passwordBuilder.append(SECURE_PASSWORD_CHARS[SECURE_RANDOM.nextInt(SECURE_PASSWORD_CHARS.length)]); } return passwordBuilder.toString(); } /** * Prepares and creates resources to be used by this KerberosOperationHandler. * Implementation in this class is ignoring parameters ldapUrl and principalContainerDn and delegate to * <code>open(KerberosCredential administratorCredentials, String defaultRealm)</code> * Subclasses that want to use these parameters need to override this method. * <p/> * It is expected that this KerberosOperationHandler will not be used before this call. * * @param administratorCredentials a KerberosCredential containing the administrative credentials * for the relevant KDC * @param defaultRealm a String declaring the default Kerberos realm (or domain) * @param kerberosConfiguration a Map of key/value pairs containing data from the kerberos-env configuration set */ public abstract void open(KerberosCredential administratorCredentials, String defaultRealm, Map<String, String> kerberosConfiguration) throws KerberosOperationException; /** * Closes and cleans up any resources used by this KerberosOperationHandler * <p/> * It is expected that this KerberosOperationHandler will not be used after this call. */ public abstract void close() throws KerberosOperationException; /** * Test to see if the specified principal exists in a previously configured KDC * <p/> * The implementation is specific to a particular type of KDC. * * @param principal a String containing the principal to test * @return true if the principal exists; false otherwise * @throws KerberosOperationException */ public abstract boolean principalExists(String principal) throws KerberosOperationException; /** * Creates a new principal in a previously configured KDC * <p/> * The implementation is specific to a particular type of KDC. * * @param principal a String containing the principal to add * @param password a String containing the password to use when creating the principal * @param service a boolean value indicating whether the principal is to be created as a service principal or not * @return an Integer declaring the generated key number * @throws KerberosOperationException */ public abstract Integer createPrincipal(String principal, String password, boolean service) throws KerberosOperationException; /** * Updates the password for an existing principal in a previously configured KDC * <p/> * The implementation is specific to a particular type of KDC. * * @param principal a String containing the principal to update * @param password a String containing the password to set * @return an Integer declaring the new key number * @throws KerberosOperationException */ public abstract Integer setPrincipalPassword(String principal, String password) throws KerberosOperationException; /** * Removes an existing principal in a previously configured KDC * <p/> * The implementation is specific to a particular type of KDC. * * @param principal a String containing the principal to remove * @return true if the principal was successfully removed; otherwise false * @throws KerberosOperationException */ public abstract boolean removePrincipal(String principal) throws KerberosOperationException; /** * Tests to ensure the connection information and credentials allow for administrative * connectivity to the KDC * * @return true of successful; otherwise false * @throws KerberosOperationException if a failure occurs while testing the * administrator credentials */ public boolean testAdministratorCredentials() throws KerberosOperationException { if (!isOpen()) { throw new KerberosOperationException("This operation handler has not been opened"); } KerberosCredential credentials = getAdministratorCredentials(); if (credentials == null) { throw new KerberosOperationException("Missing KDC administrator credentials"); } else { return principalExists(credentials.getPrincipal()); } } /** * Create a keytab using the specified principal and password. * * @param principal a String containing the principal to test * @param password a String containing the password to use when creating the principal * @param keyNumber a Integer indicating the key number for the keytab entries * @return the created Keytab * @throws KerberosOperationException */ protected Keytab createKeytab(String principal, String password, Integer keyNumber) throws KerberosOperationException { if ((principal == null) || principal.isEmpty()) { throw new KerberosOperationException("Failed to create keytab file, missing principal"); } if (password == null) { throw new KerberosOperationException( String.format("Failed to create keytab file for %s, missing password", principal)); } Set<EncryptionType> ciphers = new HashSet<EncryptionType>(keyEncryptionTypes); List<KeytabEntry> keytabEntries = new ArrayList<KeytabEntry>(); Keytab keytab = new Keytab(); if (!ciphers.isEmpty()) { // Create a set of keys and relevant keytab entries Map<EncryptionType, EncryptionKey> keys = KerberosKeyFactory.getKerberosKeys(principal, password, ciphers); if (keys != null) { byte keyVersion = (keyNumber == null) ? 0 : keyNumber.byteValue(); KerberosTime timestamp = new KerberosTime(); for (EncryptionKey encryptionKey : keys.values()) { keytabEntries.add(new KeytabEntry(principal, 1, timestamp, keyVersion, encryptionKey)); } keytab.setEntries(keytabEntries); } } return keytab; } /** * Create or append to a keytab file using keytab data from another keytab file. * <p/> * If the destination keytab file contains keytab data, that data will be merged with the new data * to create a composite set of keytab entries. * * @param sourceKeytabFile a File containing the absolute path to the file with the keytab data to store * @param destinationKeytabFile a File containing the absolute path to where the keytab data is to be stored * @return true if the keytab file was successfully created; false otherwise * @throws KerberosOperationException * @see #createKeytabFile(org.apache.directory.server.kerberos.shared.keytab.Keytab, java.io.File) */ protected boolean createKeytabFile(File sourceKeytabFile, File destinationKeytabFile) throws KerberosOperationException { return createKeytabFile(readKeytabFile(sourceKeytabFile), destinationKeytabFile); } /** * Create or append to a keytab file using the specified principal and password. * <p/> * If the destination keytab file contains keytab data, that data will be merged with the new data * to create a composite set of keytab entries. * * @param principal a String containing the principal to test * @param password a String containing the password to use when creating the principal * @param keyNumber an Integer declaring the relevant key number to use for the keytabs entries * @param destinationKeytabFile a File containing the absolute path to where the keytab data is to be stored * @return true if the keytab file was successfully created; false otherwise * @throws KerberosOperationException * @see #createKeytabFile(org.apache.directory.server.kerberos.shared.keytab.Keytab, java.io.File) */ protected boolean createKeytabFile(String principal, String password, Integer keyNumber, File destinationKeytabFile) throws KerberosOperationException { return createKeytabFile(createKeytab(principal, password, keyNumber), destinationKeytabFile); } /** * Create or append to a keytab file using the specified Keytab * <p/> * If the destination keytab file contains keytab data, that data will be merged with the new data * to create a composite set of keytab entries. * * @param keytab the Keytab containing the data to add to the keytab file * @param destinationKeytabFile a File containing the absolute path to where the keytab data is to be stored * @return true if the keytab file was successfully created; false otherwise * @throws KerberosOperationException */ protected boolean createKeytabFile(Keytab keytab, File destinationKeytabFile) throws KerberosOperationException { if (destinationKeytabFile == null) { throw new KerberosOperationException("The destination file path is null"); } try { mergeKeytabs(readKeytabFile(destinationKeytabFile), keytab).write(destinationKeytabFile); return true; } catch (IOException e) { String message = "Failed to export keytab file"; LOG.error(message, e); if (!destinationKeytabFile.delete()) { destinationKeytabFile.deleteOnExit(); } throw new KerberosOperationException(message, e); } } /** * Merge the keytab data from one keytab with the keytab data from a different keytab. * <p/> * If similar key entries exist for the same principal, the updated values will be used * * @param keytab a Keytab with the base keytab data * @param updates a Keytab containing the updated keytab data * @return a Keytab with the merged data */ protected Keytab mergeKeytabs(Keytab keytab, Keytab updates) { List<KeytabEntry> keytabEntries = (keytab == null) ? Collections.<KeytabEntry>emptyList() : new ArrayList<KeytabEntry>(keytab.getEntries()); List<KeytabEntry> updateEntries = (updates == null) ? Collections.<KeytabEntry>emptyList() : new ArrayList<KeytabEntry>(updates.getEntries()); List<KeytabEntry> mergedEntries = new ArrayList<KeytabEntry>(); if (keytabEntries.isEmpty()) { mergedEntries.addAll(updateEntries); } else if (updateEntries.isEmpty()) { mergedEntries.addAll(keytabEntries); } else { Iterator<KeytabEntry> iterator = keytabEntries.iterator(); while (iterator.hasNext()) { KeytabEntry keytabEntry = iterator.next(); for (KeytabEntry entry : updateEntries) { if (entry.getPrincipalName().equals(keytabEntry.getPrincipalName()) && entry.getKey().getKeyType().equals(keytabEntry.getKey().getKeyType())) { iterator.remove(); break; } } } mergedEntries.addAll(keytabEntries); mergedEntries.addAll(updateEntries); } Keytab mergedKeytab = new Keytab(); mergedKeytab.setEntries(mergedEntries); return mergedKeytab; } /** * Reads a file containing keytab data into a new Keytab * * @param file A File containing the path to the file from which to read keytab data * @return a Keytab or null if the file was not readable */ protected Keytab readKeytabFile(File file) { Keytab keytab; if (file.exists() && file.canRead() && (file.length() > 0)) { try { keytab = Keytab.read(file); } catch (IOException e) { // There was an issue reading in the existing keytab file... quietly assume no data keytab = null; } } else { keytab = null; } return keytab; } public KerberosCredential getAdministratorCredentials() { return administratorCredentials; } /** * Sets the administrator credentials for this KerberosOperationHandler. * <p/> * If the supplied {@link KerberosCredential} is not <code>null</code>, validates that the administrator * principal is not <code>null</code> or empty and that either the password or the keytab value * is not <code>null</code> or empty. If the credential value does not validate, then a * {@link KerberosAdminAuthenticationException} will be thrown. * * @param administratorCredentials the relevant KerberosCredential * @throws KerberosAdminAuthenticationException if the non-null KerberosCredential fails contain * a non-empty principal and a non-empty password or * keytab value. */ public void setAdministratorCredentials(KerberosCredential administratorCredentials) throws KerberosAdminAuthenticationException { // Ensure the KerberosCredential is not null if (administratorCredentials == null) { throw new KerberosAdminAuthenticationException("The administrator credential must not be null"); } String value; // Ensure the principal is not null or empty value = administratorCredentials.getPrincipal(); if ((value == null) || value.isEmpty()) { throw new KerberosAdminAuthenticationException("Must specify a principal but it is null or empty"); } // Ensure either the password or the keytab value is not null or empty value = administratorCredentials.getPassword(); if ((value == null) || value.isEmpty()) { value = administratorCredentials.getKeytab(); if ((value == null) || value.isEmpty()) { throw new KerberosAdminAuthenticationException( "Must specify either a password or a keytab but both are null or empty"); } } this.administratorCredentials = administratorCredentials; } public String getDefaultRealm() { return defaultRealm; } public void setDefaultRealm(String defaultRealm) { this.defaultRealm = defaultRealm; } /** * Gets the encryption algorithms used to encrypt keys in keytab entries * * @return a Set of EncryptionKey values indicating which algorithms are to be used when * encrypting keys for keytab entries. */ public Set<EncryptionType> getKeyEncryptionTypes() { return keyEncryptionTypes; } /** * Sets the encryption algorithms to use to encrypt keys in keytab entries * <p/> * If set to <code>null</code> the default set of ciphers will be used. See {@link #DEFAULT_CIPHERS} * * @param keyEncryptionTypes a Set of EncryptionKey values or null to indicate the default set */ public void setKeyEncryptionTypes(Set<EncryptionType> keyEncryptionTypes) { this.keyEncryptionTypes = new HashSet<EncryptionType>( (keyEncryptionTypes == null) ? DEFAULT_CIPHERS : keyEncryptionTypes); } /** * Test this KerberosOperationHandler to see whether is was previously open or not * * @return a boolean value indicating whether this KerberosOperationHandler was open (true) or not (false) */ public boolean isOpen() { return open; } /** * Sets whether this KerberosOperationHandler is open or not. * * @param open a boolean value indicating whether this KerberosOperationHandler was open (true) or not (false) */ public void setOpen(boolean open) { this.open = open; } /** * Given base64-encoded keytab data, decode the String to binary data and write it to a (temporary) * file. * <p/> * Upon success, a new file is created. The caller is expected to clean up this file when done * with it. * * @param keytabData a String containing base64-encoded keytab data * @return a File pointing to the decoded keytab file or null if not successful * @throws KerberosOperationException */ protected File createKeytabFile(String keytabData) throws KerberosOperationException { boolean success = false; File tempFile = null; // Create a temporary file try { tempFile = File.createTempFile("temp", ".dat"); } catch (IOException e) { LOG.error(String.format("Failed to create temporary keytab file: %s", e.getLocalizedMessage()), e); } if ((tempFile != null) && (keytabData != null)) { OutputStream fos = null; // Decoded the base64-encoded String and write it to the temporary file try { fos = new FileOutputStream(tempFile); fos.write(Base64.decodeBase64(keytabData)); success = true; } catch (FileNotFoundException e) { String message = String.format("Failed to write to temporary keytab file %s: %s", tempFile.getAbsolutePath(), e.getLocalizedMessage()); LOG.error(message, e); throw new KerberosOperationException(message, e); } catch (IOException e) { String message = String.format("Failed to write to temporary keytab file %s: %s", tempFile.getAbsolutePath(), e.getLocalizedMessage()); LOG.error(message, e); throw new KerberosOperationException(message, e); } finally { if (fos != null) { try { fos.close(); } catch (IOException e) { // Ignore this... } } // If there was an issue, clean up the file if (!success) { if (!tempFile.delete()) { tempFile.deleteOnExit(); } tempFile = null; } } } return tempFile; } /** * Executes a shell command. * <p/> * See {@link org.apache.ambari.server.utils.ShellCommandUtil#runCommand(String[])} * * @param command an array of String value representing the command and its arguments * @return a ShellCommandUtil.Result declaring the result of the operation * @throws KerberosOperationException */ protected ShellCommandUtil.Result executeCommand(String[] command) throws KerberosOperationException { if ((command == null) || (command.length == 0)) { return null; } else { try { return ShellCommandUtil.runCommand(command); } catch (IOException e) { String message = String.format("Failed to execute the command: %s", e.getLocalizedMessage()); LOG.error(message, e); throw new KerberosOperationException(message, e); } catch (InterruptedException e) { String message = String.format("Failed to wait for the command to complete: %s", e.getLocalizedMessage()); LOG.error(message, e); throw new KerberosOperationException(message, e); } } } /** * Given a principal, attempt to create a new DeconstructedPrincipal * * @param principal a String containing the principal to deconstruct * @return a DeconstructedPrincipal * @throws KerberosOperationException */ protected DeconstructedPrincipal createDeconstructPrincipal(String principal) throws KerberosOperationException { try { return DeconstructedPrincipal.valueOf(principal, getDefaultRealm()); } catch (IllegalArgumentException e) { throw new KerberosOperationException(e.getMessage(), e); } } /** * Given a cipher (or algorithm) name, attempts to translate it into an EncryptionType value. * <p/> * If a translation is not able to be made, {@link org.apache.directory.shared.kerberos.codec.types.EncryptionType#UNKNOWN} * is returned. * * @param name a String containing the name of the cipher to translate * @return an EncryptionType */ protected Set<EncryptionType> translateEncryptionType(String name) { Set<EncryptionType> encryptionTypes = null; if ((name != null) && !name.isEmpty()) { encryptionTypes = ENCRYPTION_TYPE_TRANSLATION_MAP.get(name.toLowerCase()); } return (encryptionTypes == null) ? Collections.<EncryptionType>emptySet() : encryptionTypes; } /** * Given a delimited set of encryption type names, attempts to translate into a set of EncryptionType * values. * * @param names a String containing a delimited list of encryption type names * @param delimiter a String declaring the delimiter to use to split names, if null, " " is used. * @return a Set of EncryptionType values */ protected Set<EncryptionType> translateEncryptionTypes(String names, String delimiter) { Set<EncryptionType> encryptionTypes = new HashSet<EncryptionType>(); if ((names != null) && !names.isEmpty()) { for (String name : names.split((delimiter == null) ? "\\s+" : delimiter)) { encryptionTypes.addAll(translateEncryptionType(name.trim())); } } return encryptionTypes; } /** * Iterates through the characters in a string to escape special characters * * @param string the String to process * @param charactersToEscape a Set of characters declaring the special characters to escape * @param escapeCharacter a character to use for escaping * @return the string with escaped characters */ protected String escapeCharacters(String string, Set<Character> charactersToEscape, Character escapeCharacter) { if ((string == null) || string.isEmpty() || (charactersToEscape == null) || charactersToEscape.isEmpty()) { return string; } else { StringBuilder builder = new StringBuilder(); for (char character : string.toCharArray()) { if (charactersToEscape.contains(character)) { builder.append(escapeCharacter); } builder.append(character); } return builder.toString(); } } }