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 */
018
019 package org.apache.hadoop.crypto.key;
020
021 import java.io.IOException;
022 import java.net.URI;
023 import java.net.URISyntaxException;
024 import java.util.ArrayList;
025 import java.util.Iterator;
026 import java.util.List;
027 import java.util.ServiceLoader;
028
029 import org.apache.hadoop.classification.InterfaceAudience;
030 import org.apache.hadoop.classification.InterfaceStability;
031 import org.apache.hadoop.conf.Configuration;
032
033 /**
034 * A factory to create a list of KeyProvider based on the path given in a
035 * Configuration. It uses a service loader interface to find the available
036 * KeyProviders and create them based on the list of URIs.
037 */
038 @InterfaceAudience.Public
039 @InterfaceStability.Unstable
040 public abstract class KeyProviderFactory {
041 public static final String KEY_PROVIDER_PATH =
042 "hadoop.security.key.provider.path";
043
044 public abstract KeyProvider createProvider(URI providerName,
045 Configuration conf
046 ) throws IOException;
047
048 private static final ServiceLoader<KeyProviderFactory> serviceLoader =
049 ServiceLoader.load(KeyProviderFactory.class,
050 KeyProviderFactory.class.getClassLoader());
051
052 // Iterate through the serviceLoader to avoid lazy loading.
053 // Lazy loading would require synchronization in concurrent use cases.
054 static {
055 Iterator<KeyProviderFactory> iterServices = serviceLoader.iterator();
056 while (iterServices.hasNext()) {
057 iterServices.next();
058 }
059 }
060
061 public static List<KeyProvider> getProviders(Configuration conf
062 ) throws IOException {
063 List<KeyProvider> result = new ArrayList<KeyProvider>();
064 for(String path: conf.getStringCollection(KEY_PROVIDER_PATH)) {
065 try {
066 URI uri = new URI(path);
067 KeyProvider kp = get(uri, conf);
068 if (kp != null) {
069 result.add(kp);
070 } else {
071 throw new IOException("No KeyProviderFactory for " + uri + " in " +
072 KEY_PROVIDER_PATH);
073 }
074 } catch (URISyntaxException error) {
075 throw new IOException("Bad configuration of " + KEY_PROVIDER_PATH +
076 " at " + path, error);
077 }
078 }
079 return result;
080 }
081
082 /**
083 * Create a KeyProvider based on a provided URI.
084 *
085 * @param uri key provider URI
086 * @param conf configuration to initialize the key provider
087 * @return the key provider for the specified URI, or <code>NULL</code> if
088 * a provider for the specified URI scheme could not be found.
089 * @throws IOException thrown if the provider failed to initialize.
090 */
091 public static KeyProvider get(URI uri, Configuration conf)
092 throws IOException {
093 KeyProvider kp = null;
094 for (KeyProviderFactory factory : serviceLoader) {
095 kp = factory.createProvider(uri, conf);
096 if (kp != null) {
097 break;
098 }
099 }
100 return kp;
101 }
102
103 }