HBase api 客户端报Permission denied

keywor:org.apache.hadoop.hbase.security.AccessDeniedException: Insufficient permissions (user=jetty, scope=default:pant
est1, params=[table=default:pantest1],action=CREATE)html

错误的详细描述以下:java

org.apache.hadoop.security.AccessControlException: org.apache.hadoop.security .AccessControlException: Permission denied: user=Administrator, access=WRITE, inode="hadoop": hadoop:supergroup:rwxr-xr-xnode

其实这个错误的缘由很容易看出来,用户Administator在hadoop上执行写操做时被权限系统拒绝.apache

解决问题的过程

看到这个错误的,第一步就是将这个错误直接入放到百度google里面进行搜索。找到了N多篇文章,可是主要的思路就如此篇文章所写的两个解决办法:http://www.cnblogs.com/acmy/archive/2011/10/28/2227901.html安全

一、在hdfs的配置文件中,将dfs.permissions修改成False服务器

二、执行这样的操做 hadoop fs -chmod 777 /user/hadoopeclipse

对于上面的第一个方法,我试了行不通,不知道是本身设置错误仍是其余缘由,对我此法不可行,第二个方法可行。第二个方法是让咱们来修改HDFS中相应文件夹的权限,后面的/user/hadoop这个路径为HDFS中的文件路径,这样修改以后就让咱们的administrator有在HDFS的相应目录下有写文件的权限(全部的用户都是写权限)。函数

虽然上面的第二步能够解决问题了,上传以后的文件全部者为Administrator,可是总感受这样的方法不够优雅,并且这样修改权限会有必定的安全问题,总之就是看着不爽,就在想有没有其余的办法?oop

问题分析

开始仔细的观察了这个错误的详细信息,看到user=Administrator, access=WRITE。这里的user实际上是我当前系统(运行客户端的计算机的操做系统)的用户名,实际指望这里的user=hadoop(hadoop是个人HADOOP上面的用户名),可是它取的是当前的系统的用户名,很明显,若是我将当前系统的用户名改成hadoop,这个确定也是能够行得通的,可是若是后期将开发的代码部署到服务器上以后,就不能方便的修改用户,此方法明显也不够方便。google

如今就想着Configuration这个是一个配置类,有没有一个参数是能够在某个地方设置以哪一个用户运行呢?搜索了半天,无果。没有找到相关的配置参数。

最终只有继续分析代码, FileSystem fs = FileSystem.get(URI.create(dest), conf);代码是在此处开始对HDFS进行调用,因此就想着将HADOOP的源码下下来,debug整个调用过程,这个user=Administator是在什么时间赋予的值。理解了调用过程,还怕找不到解决问题的办法么?

跟踪代码进入 FileSystem.get-->CACHE.get()-->Key key = new Key(uri, conf);到这里的时候发现key值里面已经有Administrator了,因此关键确定是在new key的过程。继续跟踪UserGroupInformation.getCurrentUser()-->getLoginUser()-->login.login()到这一步的时候发现用户名已经肯定了,可是这个方法是Java的核心源码,是一个通用的安全认证,但对这一块不熟悉,可是debug时看到subject里面有NTUserPrincipal:Administator,因此就想着搜索一下这个东西是啥,结果就找到了下面这一篇关键的文章:

http://www.udpwork.com/item/7047.html

在此篇文章里面做者分析了hadoop的整个登陆过程,对于我有用的是其中的这一段:

2.login.login();
这个会调用HadoopLoginModule的login()和commit()方法。
HadoopLoginModule的login()方法是一个空函数,只打印了一行调试日志 LOG.debug("hadoop login");
commit()方法负责把Principal添加到Subject中。
此时一个首要问题是username是什么?
在使用了kerberos的状况下,从javax.security.auth.kerberos.KerberosPrincipal的实例获取username。
在未使用kerberos的状况下,优先读取HADOOP_USER_NAME这个系统环境变量,若是不为空,那么拿它做username。不然,读取HADOOP_USER_NAME这个java环境变量。不然,从com.sun.security.auth.NTUserPrincipal或者com.sun.security.auth.UnixPrincipal的实例获取username。
若是以上尝试都失败,那么抛出异常LoginException("Can’t find user name")。
最终拿username构造org.apache.hadoop.security.User的实例添加到Subject中。

看完这一段,我明白了执行login.login的时候调用了hadoop里面的HadoopLoginModule方法,而关键是在commit方法里面,在这里优先读取HADOOP_USER_NAME系统环境变量,而后是java环境变量,若是再没有就从NTUserPrincipal等里面取。关键代码为:

  1. if (!isSecurityEnabled() && (user == null)) {
  2.   String envUser = System.getenv(HADOOP_USER_NAME);
  3.   if (envUser == null) {
  4.     envUser = System.getProperty(HADOOP_USER_NAME);
  5.   }
  6.   user = envUser == null ? null : new User(envUser);
  7. }

OK,看到这里个人需求也就解决了,只要在系统的环境变量里面添加HADOOP_USER_NAME=hadoop(HDFS上的有权限的用户,具体看本身的状况),或者在当前JDK的变量参数里面添加HADOOP_USER_NAME这个Java变量便可。个人状况添加系统环境变量更方法。

若是是在Eclipse里面运行,修改完环境变量后,记得重启一下eclipse,否则可能不会生效。

解决办法

最终,总结下来解决办法大概有三种:

一、在系统的环境变量或java JVM变量里面添加HADOOP_USER_NAME,这个值具体等于多少看本身的状况,之后会运行HADOOP上的Linux的用户名。(修改完重启eclipse,否则可能不生效)

二、将当前系统的账号修改成hadoop

三、使用HDFS的命令行接口修改相应目录的权限,hadoop fs -chmod 777 /user,后面的/user是要上传文件的路径,不一样的状况可能不同,好比要上传的文件路径为hdfs://namenode/user/xxx.doc,则这样的修改能够,若是要上传的文件路径为hdfs://namenode/java/xxx.doc,则要修改的为hadoop fs -chmod 777 /java或者hadoop fs -chmod 777 /,java的那个须要先在HDFS里面创建Java目录,后面的这个是为根目录调整权限。

我喜欢第一个方法。

相关文章
相关标签/搜索