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.security.alias;
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.List;
026    import java.util.ServiceLoader;
027    
028    import org.apache.hadoop.classification.InterfaceAudience;
029    import org.apache.hadoop.classification.InterfaceStability;
030    import org.apache.hadoop.conf.Configuration;
031    
032    /**
033     * A factory to create a list of CredentialProvider based on the path given in a
034     * Configuration. It uses a service loader interface to find the available
035     * CredentialProviders and create them based on the list of URIs.
036     */
037    @InterfaceAudience.Public
038    @InterfaceStability.Unstable
039    public abstract class CredentialProviderFactory {
040      public static final String CREDENTIAL_PROVIDER_PATH =
041          "hadoop.security.credential.provider.path";
042    
043      public abstract CredentialProvider createProvider(URI providerName,
044                                                 Configuration conf
045                                                 ) throws IOException;
046    
047      private static final ServiceLoader<CredentialProviderFactory> serviceLoader =
048          ServiceLoader.load(CredentialProviderFactory.class);
049    
050      public static List<CredentialProvider> getProviders(Configuration conf
051                                                   ) throws IOException {
052        List<CredentialProvider> result = new ArrayList<CredentialProvider>();
053        for(String path: conf.getStringCollection(CREDENTIAL_PROVIDER_PATH)) {
054          try {
055            URI uri = new URI(path);
056            boolean found = false;
057            for(CredentialProviderFactory factory: serviceLoader) {
058              CredentialProvider kp = factory.createProvider(uri, conf);
059              if (kp != null) {
060                result.add(kp);
061                found = true;
062                break;
063              }
064            }
065            if (!found) {
066              throw new IOException("No CredentialProviderFactory for " + uri + " in " +
067                  CREDENTIAL_PROVIDER_PATH);
068            }
069          } catch (URISyntaxException error) {
070            throw new IOException("Bad configuration of " + CREDENTIAL_PROVIDER_PATH +
071                " at " + path, error);
072          }
073        }
074        return result;
075      }
076    }