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 */
018package org.apache.hadoop.hbase.security;
019
020import java.io.IOException;
021import java.util.Collection;
022import org.apache.hadoop.conf.Configuration;
023import org.apache.hadoop.hbase.AuthUtil;
024import org.apache.yetus.audience.InterfaceAudience;
025import org.slf4j.Logger;
026import org.slf4j.LoggerFactory;
027
028import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableSet;
029
030/**
031 * Keeps lists of superusers and super groups loaded from HBase configuration, checks if certain
032 * user is regarded as superuser.
033 */
034@InterfaceAudience.Private
035public final class Superusers {
036  private static final Logger LOG = LoggerFactory.getLogger(Superusers.class);
037
038  /** Configuration key for superusers */
039  public static final String SUPERUSER_CONF_KEY = "hbase.superuser"; // Not getting a name
040
041  private static ImmutableSet<String> superUsers;
042  private static ImmutableSet<String> superGroups;
043  private static User systemUser;
044
045  private Superusers() {
046  }
047
048  /**
049   * Should be called only once to pre-load list of super users and super groups from Configuration.
050   * This operation is idempotent.
051   * @param conf configuration to load users from
052   * @throws IOException           if unable to initialize lists of superusers or super groups
053   * @throws IllegalStateException if current user is null
054   */
055  public static void initialize(Configuration conf) throws IOException {
056    ImmutableSet.Builder<String> superUsersBuilder = ImmutableSet.builder();
057    ImmutableSet.Builder<String> superGroupsBuilder = ImmutableSet.builder();
058    systemUser = User.getCurrent();
059
060    if (systemUser == null) {
061      throw new IllegalStateException("Unable to obtain the current user, "
062        + "authorization checks for internal operations will not work correctly!");
063    }
064
065    String currentUser = systemUser.getShortName();
066    LOG.trace("Current user name is {}", currentUser);
067    superUsersBuilder.add(currentUser);
068
069    String[] superUserList = conf.getStrings(SUPERUSER_CONF_KEY, new String[0]);
070    for (String name : superUserList) {
071      if (AuthUtil.isGroupPrincipal(name)) {
072        // Let's keep the '@' for distinguishing from user.
073        superGroupsBuilder.add(name);
074      } else {
075        superUsersBuilder.add(name);
076      }
077    }
078    superUsers = superUsersBuilder.build();
079    superGroups = superGroupsBuilder.build();
080  }
081
082  /**
083   * Check if the current user is a super user
084   * @return true if current user is a super user (whether as user running process, declared as
085   *         individual superuser or member of supergroup), false otherwise.
086   * @param user to check
087   * @throws IllegalStateException if lists of superusers/super groups haven't been initialized
088   *                               properly
089   */
090  public static boolean isSuperUser(User user) {
091    if (superUsers == null) {
092      throw new IllegalStateException(
093        "Super users/super groups lists" + " have not been initialized properly.");
094    }
095    if (user == null) {
096      throw new IllegalArgumentException("Null user passed for super user check");
097    }
098    if (superUsers.contains(user.getShortName())) {
099      return true;
100    }
101    for (String group : user.getGroupNames()) {
102      if (superGroups.contains(AuthUtil.toGroupEntry(group))) {
103        return true;
104      }
105    }
106    return false;
107  }
108
109  /**
110   * Check if the current user is a super user
111   * @return true if current user is a super user, false otherwise.
112   * @param user to check
113   */
114  public static boolean isSuperUser(String user) {
115    return superUsers.contains(user) || superGroups.contains(user);
116  }
117
118  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "MS_EXPOSE_REP",
119      justification = "immutable")
120  public static Collection<String> getSuperUsers() {
121    return superUsers;
122  }
123
124  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "MS_EXPOSE_REP",
125      justification = "immutable")
126  public static Collection<String> getSuperGroups() {
127    return superGroups;
128  }
129
130  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "MS_EXPOSE_REP",
131      justification = "by design")
132  public static User getSystemUser() {
133    return systemUser;
134  }
135}