
# 调用REST接口访问HBase应用安全认证
#### 场景说明
HBase服务安装时可选部署RESTServer实例，可通过访问HBase REST服务的形式调用HBase相关操作，包括对Namespace、table的操作等。访问HBase REST服务同样需要进行Kerberos认证。
该场景下不需要进行初始化配置，仅需要用于Kerberos安全认证的keytab文件和krb5.conf文件。具体使用方法在样例代码的"README.md"中会有详细说明。
以下代码在hbase-rest-example样例工程的"com.huawei.bigdata.hbase.examples"包的"HBaseRestTest"类中。
- 代码认证 请根据实际情况，修改**"** principal**"**为实际用户名，例如"developuser"。
  在Windows环境下和Linux环境下请使用对应的路径获取方式。
  ```
  //In Windows environment
          String userdir = HBaseRestTest.class.getClassLoader().getResource("conf").getPath() + File.separator;[1]
          //In Linux environment
          //String userdir = System.getProperty("user.dir") + File.separator + "conf" + File.separator;
          String principal = "hbaseuser1";
          login(principal, userKeytabFile, krb5File);
          // RESTServer's hostname.
          String restHostName = "10.120.16.170";[2]
          String securityModeUrl = new StringBuilder("https://").append(restHostName).append(":21309").toString();
          String nonSecurityModeUrl = new StringBuilder("http://").append(restHostName).append(":21309").toString();
          HBaseRestTest test = new HBaseRestTest();
          //If cluster is non-security mode，use nonSecurityModeUrl as  parameter.
          test.test(securityModeUrl);[3]
  ```
  MRS 3.6.0-LTS及之后版本：
  ```
  //In Windows environment
          String userdir = HBaseRestTest.class.getClassLoader().getResource("conf").getPath() + File.separator;[1]
          //In Linux environment
          //String userdir = System.getProperty("user.dir") + File.separator + "conf" + File.separator;
          String principal = "developuser";
          login(principal, userKeytabFile, krb5File);
   
          // Specify the Rest server hostnames, separated by comma if multiple are there.[2]
          String restServerHostNames = "xxx.xxx.xxx.x,xxx.xxx.xxx.xx,xxx.xxx.xxx.xxx";
          for (String hostname : restServerHostNames.split(",")) {
              try {
                  String securityModeUrl = new StringBuilder("https://").append(hostname).append(":21309").toString();
                  String nonSecurityModeUrl = new StringBuilder("http://").append(hostname).append(":21309").toString();
                  HBaseRestTest test = new HBaseRestTest();
                  //If cluster is non-security mode，use nonSecurityModeUrl as parameter.
                  test.test(securityModeUrl);[3]
                  break;
              } catch (IOException e) {
                  LOG.error("Failed to connect to the host: {}, retrying with other servers if any", hostname, e);
              }
          }
  ```
  \[1\]**userdir**获取的是编译后资源路径下conf目录的路径。用于安全认证的用户凭证文件需要放置到"src/main/resources/conf"的目录下。若不存在conf目录，请自行创建。
  \[2\]修改**restHostName**为待访问的RestServer实例所在节点IP地址，建议部署多个RESTServer增加业务可靠性，多个RESTServer IP以逗号进行分隔，并将访问节点IP配置到运行样例代码的本机hosts文件中。
  \[3\]安全模式采用https模式进行访问HBase REST服务，传入"securityModeUrl"作为test.test()参数。
  
- 安全登录
  ```
  private static void login(String principal, String userKeytabFile, String krb5File) throws LoginException {
          Map<String, String> options = new HashMap<>();
          options.put("useTicketCache", "false");
          options.put("useKeyTab", "true");
          options.put("keyTab", userKeytabFile);
   
          /**
           * Krb5 in GSS API needs to be refreshed so it does not throw the error
           * Specified version of key is not available
           */
   
          options.put("refreshKrb5Config", "true");
          options.put("principal", principal);
          options.put("storeKey", "true");
          options.put("doNotPrompt", "true");
          options.put("isInitiator", "true");
          options.put("debug", "true");
          System.setProperty("java.security.krb5.conf", krb5File);
          Configuration config = new Configuration() {
              @Override
              public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
                  return new AppConfigurationEntry[] {
                      new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule",
                          AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options)
                  };
              }
          };
          subject = new Subject(false, Collections.singleton(new KerberosPrincipal(principal)), Collections.EMPTY_SET,
              Collections.EMPTY_SET);
          LoginContext loginContext = new LoginContext("Krb5Login", subject, null, config);
          loginContext.login();
  }
  ```
  
 
