解决:org.apache.hadoop.security.AccessControlException: Client cannot authenticate via:[TOKEN, KERB...

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.fs.permission.AclStatus;
import org.apache.hadoop.security.UserGroupInformation;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

public class HdfsKerberosDemo {

    public static void main(String[] args) throws IOException {

        // -Djava.security.krb5.conf=/home/xxx/kerberos/krb5.conf
        // -Dkeytab.path=/home/xxx/kerberos/hive.service.keytab
        String krb5File = "/xxx/krb5.conf";
        String fileName = krb5File.substring(krb5File.lastIndexOf("/")+1);
        String tempConfPath = "/root/temp/" + fileName;
        try {
            download(krb5File, tempConfPath);
        } catch (IOException e) {

            File folder = new File("/root/temp");
            String[] files = folder.list();
            boolean fileExists = false;

            if (files != null) {
                for (String file : files) {
                    if (file.equals(fileName)) {
                        fileExists = true;
                        break;
                    }
                }
            }

            if (fileExists) {
                //log.info("-------------------krb5conf文件存在-------------");
                try {
                    Files.delete(Paths.get(tempConfPath));
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
            }

            throw new RuntimeException("获取krb5.conf文件失败");
        }
        /** 设置krb5.conf到环境变量*/
        System.setProperty("java.security.krb5.conf", tempConfPath);
        String keytabFile = "/xxx/krb5.conf";
        String keytabName = keytabFile.substring(keytabFile.lastIndexOf("/")+1);
        String tempKeytabPath = "/root/temp/" + keytabName;
        try {
            download(keytabFile, tempKeytabPath);
        } catch (IOException e) {

            File folder = new File("/root/temp");
            String[] files = folder.list();
            boolean fileExists = false;

            if (files != null) {
                for (String file : files) {
                    if (file.equals(keytabName)) {
                        fileExists = true;
                        break;
                    }
                }
            }

            if (fileExists) {
                //log.info("-------------------krb5conf文件存在-------------");
                try {
                    Files.delete(Paths.get(tempKeytabPath));
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
            }

            throw new RuntimeException("获取krb5.conf文件失败");
        }
        System.setProperty("keytab.path", tempKeytabPath);
        // 加载Hadoop配置
        Configuration configuration = new Configuration();

        configuration.addResource(new Path(HdfsKerberosExample.class.getClassLoader().getResource("core-site.xml").getPath()));
        configuration.addResource(new Path(HdfsKerberosExample.class.getClassLoader().getResource("hdfs-site.xml").getPath()));
        // 检测kerberos认证配置文件
        String krb5conf = System.getProperty("java.security.krb5.conf");
        String keytabPath = System.getProperty("keytab.path");
        if (krb5conf == null) {
            System.out.println("未找到krb5.conf,请配置VMOptions[java.security.krb5.conf]");
            return;
        } else if (keytabPath == null) {
            System.out.println("未找到krb5.conf,请配置VMOptions[keytab.path]");
            return;
        }
        System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
        configuration.set("fs.defaultFS", "hdfs://xxxx");  //HDFS地址
        //configuration.setClassLoader(org.apache.hadoop.hdfs.DistributedFileSystem.class.getClassLoader());
        configuration.set("fs.file.impl", org.apache.hadoop.fs.LocalFileSystem.class.getName());
        configuration.set("fs.hdfs.impl", org.apache.hadoop.hdfs.DistributedFileSystem.class.getName());
        // 启用keytab renewal
        configuration.set("hadoop.kerberos.keytab.login.autorenewal.enabled", "true");
        configuration.set("hadoop.security.authentication", "Kerberos");

        // 使用UserGroupInformation进行认证
        UserGroupInformation.setConfiguration(configuration);
        UserGroupInformation.loginUserFromKeytab("hive/datasophon01@HADOOP.COM", keytabPath);

        System.out.println("====== 打印当前登录用户 START =====");
        //System.out.println("user:" + UserGroupInformation.getCurrentUser());
        System.out.println("====== 打印当前登录用户 END =====\n");

        // 创建FileSystem实例
        FileSystem fileSystem = FileSystem.get(configuration);
        // 创建根路径
        Path rootPath = new Path("/data");

        System.out.println("====== ACL =====");
        // 打印 ACL 内容
        /*AclStatus aclStatus = fileSystem.getAclStatus(rootPath);
        System.out.println(aclStatus);
        System.out.println();*/
        System.out.println(fileSystem.getStatus(new Path("/data")));


        System.out.println("======= ROOT(/) Files ======");
        RemoteIterator<LocatedFileStatus> list = FileSystem.get(configuration).listFiles(rootPath,true);
        while (list.hasNext()){
            LocatedFileStatus fileStatus =list.next();
            System.out.println("文件路径为" + fileStatus.getPath());
        }
        /*RemoteIterator<LocatedFileStatus> fileStatus = fileSystem.listFiles(rootPath,true);
        System.out.println("成功获取文件系统,正在导出文件系统内容,请稍后...");
        FileWriter writer = new FileWriter("hdfs-files.txt");
        while (fileStatus.hasNext()){
            LocatedFileStatus st = fileStatus.next();
            writer.write(st.getPath().toString());
        }
        writer.close();*/
        System.out.println("hdfs文件内容写入成功");


        // 关闭认证用户
        // UserGroupInformation.getLoginUser().logout();
        UserGroupInformation.getLoginUser().logoutUserFromKeytab();
    }

    private static void download(String url, String localPath) throws IOException {
        URL website = new URL(url);
        try (InputStream in = website.openStream()) {
            Files.copy(in, Paths.get(localPath), StandardCopyOption.REPLACE_EXISTING);
        }
    }
}

win11上执行上述代码正常,但在linux服务器上执行同样的代码,用FileSystem Client去操作HDFS文件的时候,应用报如下的错误:org.apache.hadoop.security.AccessControlException: Client cannot authenticate via:[TOKEN, KERBERO]。
在确认了集群已经是开启Kerberos认证之后,去看详细的日志相关信息,看到了如下的提示:

Login successful for user hdfs/xxxx@xxx.COM using keytab file /root/temp/xxxKEYTABFILE
说明应用端的Kerberos认证其实已经通过了,但是在操作HDFS文件的时候为什么还是报了Client cannot authenticate via:[TOKEN, KERBEROS]的错。
解决:换成如下代码

                String krb5File = "/xxx/krb5.conf";
        String fileName = krb5File.substring(krb5File.lastIndexOf("/")+1);
        String tempConfPath = "D:\\Download\\" + fileName;
        try {
            download(krb5File, tempConfPath);
        } catch (IOException e) {

            File folder = new File("D:\\Download");
            String[] files = folder.list();
            boolean fileExists = false;

            if (files != null) {
                for (String file : files) {
                    if (file.equals(fileName)) {
                        fileExists = true;
                        break;
                    }
                }
            }

            if (fileExists) {
                //log.info("-------------------krb5conf文件存在-------------");
                try {
                    Files.delete(Paths.get(tempConfPath));
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
            }

            throw new RuntimeException("获取krb5.conf文件失败");
        }
        /** 设置krb5.conf到环境变量*/
        System.setProperty("java.security.krb5.conf", tempConfPath);
        String keytabFile = "/xxx/krb5.conf";
        String keytabName = keytabFile.substring(keytabFile.lastIndexOf("/")+1);
        String tempKeytabPath = "D:\\Download\\" + keytabName;
        try {
            download(keytabFile, tempKeytabPath);
        } catch (IOException e) {

            File folder = new File("D:\\Download");
            String[] files = folder.list();
            boolean fileExists = false;

            if (files != null) {
                for (String file : files) {
                    if (file.equals(keytabName)) {
                        fileExists = true;
                        break;
                    }
                }
            }

            if (fileExists) {
                //log.info("-------------------krb5conf文件存在-------------");
                try {
                    Files.delete(Paths.get(tempKeytabPath));
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
            }

            throw new RuntimeException("获取krb5.conf文件失败");
        }
        System.setProperty("keytab.path", tempKeytabPath);
        // 加载Hadoop配置
        Configuration configuration = new Configuration();

        configuration.addResource(new Path(HdfsKerberosExample.class.getClassLoader().getResource("core-site.xml").getPath()));
        configuration.addResource(new Path(HdfsKerberosExample.class.getClassLoader().getResource("hdfs-site.xml").getPath()));
        // 检测kerberos认证配置文件
        String krb5conf = System.getProperty("java.security.krb5.conf");
        String keytabPath = System.getProperty("keytab.path");
        if (krb5conf == null) {
            System.out.println("未找到krb5.conf,请配置VMOptions[java.security.krb5.conf]");
            return;
        } else if (keytabPath == null) {
            System.out.println("未找到krb5.conf,请配置VMOptions[keytab.path]");
            return;
        }
                System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
                configuration.set("fs.defaultFS", "hdfs://" + linkParameter.getHdfsAddress());  //HDFS地址
                configuration.set("fs.file.impl", org.apache.hadoop.fs.LocalFileSystem.class.getName());
                //configuration.set("fs.hdfs.impl", org.apache.hadoop.hdfs.DistributedFileSystem.class.getName());
                Thread.currentThread().setContextClassLoader(org.apache.hadoop.hdfs.DistributedFileSystem.class.getClassLoader());
                configuration.setClassLoader(org.apache.hadoop.hdfs.DistributedFileSystem.class.getClassLoader());
                //configuration.setClassLoader(org.apache.hadoop.hdfs.DistributedFileSystem.class.getClassLoader());
                // 启用keytab renewal
                configuration.set("hadoop.kerberos.keytab.login.autorenewal.enabled", "true");
                configuration.set("hadoop.security.authentication", taskDatasourceConfigDTO.getAuthentication());

                // 使用UserGroupInformation进行认证
        UserGroupInformation.setConfiguration(configuration);
        UserGroupInformation.loginUserFromKeytab("hive/datasophon01@HADOOP.COM", keytabPath);

        System.out.println("====== 打印当前登录用户 START =====");
        //System.out.println("user:" + UserGroupInformation.getCurrentUser());
        System.out.println("====== 打印当前登录用户 END =====\n");

        // 创建FileSystem实例
        FileSystem fileSystem = FileSystem.get(configuration);
        // 创建根路径
        Path rootPath = new Path("/data");

        System.out.println("====== ACL =====");
        // 打印 ACL 内容
        /*AclStatus aclStatus = fileSystem.getAclStatus(rootPath);
        System.out.println(aclStatus);
        System.out.println();*/
        System.out.println(fileSystem.getStatus(new Path("/data")));


        System.out.println("======= ROOT(/) Files ======");
        RemoteIterator<LocatedFileStatus> list = FileSystem.get(configuration).listFiles(rootPath,true);
        while (list.hasNext()){
            LocatedFileStatus fileStatus =list.next();
            System.out.println("文件路径为" + fileStatus.getPath());
        }
        /*RemoteIterator<LocatedFileStatus> fileStatus = fileSystem.listFiles(rootPath,true);
        System.out.println("成功获取文件系统,正在导出文件系统内容,请稍后...");
        FileWriter writer = new FileWriter("hdfs-files.txt");
        while (fileStatus.hasNext()){
            LocatedFileStatus st = fileStatus.next();
            writer.write(st.getPath().toString());
        }
        writer.close();*/
        System.out.println("hdfs文件内容写入成功");


        // 关闭认证用户
        // UserGroupInformation.getLoginUser().logout();
        UserGroupInformation.getLoginUser().logoutUserFromKeytab();

核心是如下三行

configuration.set("fs.file.impl", org.apache.hadoop.fs.LocalFileSystem.class.getName());// configuration.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem");
Thread.currentThread().setContextClassLoader(org.apache.hadoop.hdfs.DistributedFileSystem.class.getClassLoader());
configuration.setClassLoader(org.apache.hadoop.hdfs.DistributedFileSystem.class.getClassLoader());
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容