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