UserGroupInformation中的几种user介绍

举报
Lettle whale 发表于 2020/08/12 10:12:03 2020/08/12
【摘要】 UserGroupInformation中的几种User介绍

"HDFS", "MapReduce", "HBase", "Hive", "Oozie"这几个组件均使用了hadoop commonUserGroupInformation类来进行用户/组信息的处理。在这个类里面有几种用户的概念时常困扰我们,现在我们来认识一下具体有那几种用户。

首先是loginUser,在loginUserFromKeytab函数中展示的就是kerberos认证的代码:

public synchronized

  static void loginUserFromKeytab(String user, String path) throws IOException {

    if (!isSecurityEnabled())

      return;

    keytabFile = path;

    keytabPrincipal = user;

    Subject subject = new Subject();

    LoginContext login;

    long start = 0;

    try {

      login =

        newLoginContext(HadoopConfiguration.KEYTAB_KERBEROS_CONFIG_NAME, subject);

      start = System.currentTimeMillis();

      login.login();

      metrics.loginSuccess.add(System.currentTimeMillis() - start);

      loginUser = new UserGroupInformation(subject);

      loginUser.setLogin(login);

      loginUser.setAuthenticationMethod(AuthenticationMethod.KERBEROS);

    } catch (LoginException le) {

      if (start > 0) {

        metrics.loginFailure.add(System.currentTimeMillis() - start);

      }

      throw new IOException("Login failure for " + user + " from keytab " +

                            path, le);

    }

    LOG.info("Login successful for user " + keytabPrincipal

        + " using keytab file " + keytabFile);

  }

  整个认证过程就是为了生成一个login(存储这认证需要的所有信息的上下文)和subject(认证后的票据信息等均在此变量中),并且将loginsubject和一个UserGroupInformation实例关联,这个实例就是loginUser,即loginUser就代表了一个通过kerberos认证的用户。


因此对于UserGroupInformationgetLoginUser()方法,就是获取当前的loginUser实例,如果loginUser还未存在,即进行上述认证过程新生成一个loginUser

那么对于UserGroupInformationgetCurrentUser()方法与上面的getLoginUser()差别有在哪呢?

public synchronized

  static UserGroupInformation getCurrentUser() throws IOException {

    AccessControlContext context = AccessController.getContext();

    Subject subject = Subject.getSubject(context);

    if (subject == null || subject.getPrincipals(User.class).isEmpty()) {

      return getLoginUser();

    } else {

      return new UserGroupInformation(subject);

    }

}


如果通过当前的上下文(一直以来都觉得上下文是个很抽象的东西,我这里据个例子,比如代码为subjectuserA.doas {xxx},那么在xxx里面获取上下文里的subject就是subjectuserA了)已经能够获取现成的subject,那么就用当前的subject新生成一个UserGroupInformation实例返回,如果当前上下文未获取到现成的subject则调用getLoginUser()方法,新认证一个用户然后构造UserGroupInformation实例返回。

接下来UserGroupInformationgetRealUser()是最复杂的一个了,RealUser只有在Proxy认证时才会被使用到。

public static UserGroupInformation createProxyUser(String user,

      UserGroupInformation realUser) {

    if (user == null || "".equals(user)) {

      throw new IllegalArgumentException("Null user");

    }

    if (realUser == null) {

      throw new IllegalArgumentException("Null real user");

    }

    Subject subject = new Subject();

    Set<Principal> principals = subject.getPrincipals();

    principals.add(new User(user));

    principals.add(new RealUser(realUser));

    UserGroupInformation result =new UserGroupInformation(subject);

    result.setAuthenticationMethod(AuthenticationMethod.PROXY);

    return result;

  }


我们来看看org.apache.hadoop.ipc.Client的认证代码

private synchronized void setupIOstreams() throws InterruptedException {

 

  ......

 

  while (true) {

          setupConnection();

          InputStream inStream = NetUtils.getInputStream(socket);

          OutputStream outStream = NetUtils.getOutputStream(socket);

          writeConnectionHeader(outStream);

          if (useSasl) {

            final InputStream in2 = inStream;

            final OutputStream out2 = outStream;

            UserGroupInformation ticket = remoteId.getTicket();

            if (authMethod == AuthMethod.KERBEROS) {

              if (ticket.getRealUser() != null) {

                ticket = ticket.getRealUser();

              }

            }

            boolean continueSasl = false;

            try {

              continueSasl = ticket

                  .doAs(new PrivilegedExceptionAction<Boolean>() {

                    @Override

                    public Boolean run() throws IOException {

                      return setupSaslConnection(in2, out2);

                    }

                  });

            }

   ......

  }


如果当前建立RPC连接的subject存在RealUser,则RPC客户端代码会使用RealUser的票据信息来进行到服务端的认证,那么服务端识别到该用户到底是谁呢?

来看看认证服务端org.apache.hadoop.ipc.Server

private void processConnectionContext(byte[] buf) throws IOException {

 

  ......

 

  {

        // user is authenticated

        user.setAuthenticationMethod(authMethod.authenticationMethod);

        //Now we check if this is a proxy user case. If the protocol user is

        //different from the 'user', it is a proxy user scenario. However,

        //this is not allowed if user authenticated with DIGEST.

        if ((protocolUser != null)

            && (!protocolUser.getUserName().equals(user.getUserName()))) {

          if (authMethod == AuthMethod.DIGEST) {

            // Not allowed to doAs if token authentication is used

            throw new AccessControlException("Authenticated user (" + user

                + ") doesn't match what the client claims to be ("

                + protocolUser + ")");

          } else {

            // Effective user can be different from authenticated user

            // for simple auth or kerberos auth

            // The user is the real user. Now we create a proxy user

            UserGroupInformation realUser = user;

            user = UserGroupInformation.createProxyUser(protocolUser

                .getUserName(), realUser);

            // Now the user is a proxy user, set Authentication method Proxy.

            user.setAuthenticationMethod(AuthenticationMethod.PROXY);

          }

        }

      }

 

  ......

 

  }


如果客户端指明用户与服务端认证用户名不一致时,(必须是kerberos认证方式,如果是digest则不可能存在这种情况)服务端会自己根据当前用户信息创建一个ProxyUser来支撑后续业务处理。所以这里最终业务用户还是之前客户端代码中蓝色部分new User(user),只是这个用户自己没有票据而是借助了new RealUser(realUser)的票据来进行认证过程。


【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。