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.security.alias;
020
021import java.io.IOException;
022import java.net.URI;
023import java.nio.charset.StandardCharsets;
024import java.util.ArrayList;
025import java.util.List;
026
027import org.apache.hadoop.classification.InterfaceAudience;
028import org.apache.hadoop.conf.Configuration;
029import org.apache.hadoop.io.Text;
030import org.apache.hadoop.security.Credentials;
031import org.apache.hadoop.security.UserGroupInformation;
032
033/**
034 * A CredentialProvider for UGIs. It uses the credentials object associated
035 * with the current user to find credentials. This provider is created using a
036 * URI of "user:///".
037 */
038@InterfaceAudience.Private
039public class UserProvider extends CredentialProvider {
040  public static final String SCHEME_NAME = "user";
041  private final UserGroupInformation user;
042  private final Credentials credentials;
043
044  private UserProvider() throws IOException {
045    user = UserGroupInformation.getCurrentUser();
046    credentials = user.getCredentials();
047  }
048
049  @Override
050  public boolean isTransient() {
051    return true;
052  }
053
054  @Override
055  public CredentialEntry getCredentialEntry(String alias) {
056    byte[] bytes = credentials.getSecretKey(new Text(alias));
057    if (bytes == null) {
058      return null;
059    }
060    return new CredentialEntry(
061        alias, new String(bytes, StandardCharsets.UTF_8).toCharArray());
062  }
063
064  @Override
065  public CredentialEntry createCredentialEntry(String name, char[] credential) 
066      throws IOException {
067    Text nameT = new Text(name);
068    if (credentials.getSecretKey(nameT) != null) {
069      throw new IOException("Credential " + name + 
070          " already exists in " + this);
071    }
072    credentials.addSecretKey(new Text(name), 
073        new String(credential).getBytes("UTF-8"));
074    return new CredentialEntry(name, credential);
075  }
076
077  @Override
078  public void deleteCredentialEntry(String name) throws IOException {
079    byte[] cred = credentials.getSecretKey(new Text(name));
080    if (cred != null) {
081      credentials.removeSecretKey(new Text(name));
082    }
083    else {
084      throw new IOException("Credential " + name + 
085          " does not exist in " + this);
086    }
087  }
088
089  @Override
090  public String toString() {
091    return SCHEME_NAME + ":///";
092  }
093
094  @Override
095  public void flush() {
096    user.addCredentials(credentials);
097  }
098
099  public static class Factory extends CredentialProviderFactory {
100
101    @Override
102    public CredentialProvider createProvider(URI providerName,
103                                      Configuration conf) throws IOException {
104      if (SCHEME_NAME.equals(providerName.getScheme())) {
105        return new UserProvider();
106      }
107      return null;
108    }
109  }
110
111  @Override
112  public List<String> getAliases() throws IOException {
113    List<String> list = new ArrayList<String>();
114    List<Text> aliases = credentials.getAllSecretKeys();
115    for (Text key : aliases) {
116      list.add(key.toString());
117    }
118    return list;
119  }
120}