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; 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 040public 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}