【jceks】使用keytool和hadoop credential生成和解析jceks文件(无密码storepass)

build.gradle文件:

gradle 复制代码
plugins {
    id 'org.jetbrains.kotlin.jvm' version '1.9.23'
}

group = 'com.xxx.test'
version = '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.apache.hadoop:hadoop-common:3.0.0")
    testImplementation 'org.jetbrains.kotlin:kotlin-test'
}

test {
    useJUnitPlatform()
}
kotlin {
    jvmToolchain(8)
}

koltin语言编写。

ranger中的org.apache.ranger.credentialapi.CredentialReader工具类:

kotlin 复制代码
import org.apache.commons.lang3.StringUtils
import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.security.alias.CredentialProvider.CredentialEntry
import org.apache.hadoop.security.alias.CredentialProviderFactory
import org.apache.hadoop.security.alias.JavaKeyStoreProvider
import java.util.*

object CredentialReader {


    fun getDecryptedString(CrendentialProviderPath: String?, alias: String?, storeType: String?): String? {
        var CrendentialProviderPath = CrendentialProviderPath
        var alias = alias
        var credential: String? = null
        try {
            if (CrendentialProviderPath == null || alias == null) {
                return null
            }
            var pass: CharArray? = null
            val conf = Configuration()
            var crendentialProviderPrefixJceks = JavaKeyStoreProvider.SCHEME_NAME + "://file"
            val crendentialProviderPrefixLocalJceks = "localjceks://file"
            crendentialProviderPrefixJceks = crendentialProviderPrefixJceks.lowercase(Locale.getDefault())

            var crendentialProviderPrefixBcfks = "bcfks" + "://file"
            var crendentialProviderPrefixLocalBcfks = "localbcfks" + "://file"
            crendentialProviderPrefixBcfks = crendentialProviderPrefixBcfks.lowercase(Locale.getDefault())
            crendentialProviderPrefixLocalBcfks = crendentialProviderPrefixLocalBcfks.lowercase(Locale.getDefault())

            CrendentialProviderPath = CrendentialProviderPath.trim { it <= ' ' }
            alias = alias.trim { it <= ' ' }
            if (CrendentialProviderPath.lowercase(Locale.getDefault()).startsWith(crendentialProviderPrefixJceks) ||
                CrendentialProviderPath.lowercase(Locale.getDefault())
                    .startsWith(crendentialProviderPrefixLocalJceks) ||
                CrendentialProviderPath.lowercase(Locale.getDefault()).startsWith(crendentialProviderPrefixBcfks) ||
                CrendentialProviderPath.lowercase(Locale.getDefault()).startsWith(crendentialProviderPrefixLocalBcfks)
            ) {
                conf[CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH] = CrendentialProviderPath
            } else {
                if (CrendentialProviderPath.startsWith("/")) {
                    if (StringUtils.equalsIgnoreCase(storeType, "bcfks")) {
                        conf[CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH] = CrendentialProviderPath
                    } else {
                        conf[CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH] =
                            JavaKeyStoreProvider.SCHEME_NAME + "://file" + CrendentialProviderPath
                    }
                } else {
                    conf[CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH] =
                        JavaKeyStoreProvider.SCHEME_NAME + "://file/" + CrendentialProviderPath
                }
            }
            val providers = CredentialProviderFactory.getProviders(conf)
            var aliasesList: List<String?> = ArrayList()
            var credEntry: CredentialEntry? = null
            for (provider in providers) {
                //System.out.println("Credential Provider :" + provider);
                aliasesList = provider.aliases
                if (aliasesList != null && aliasesList.contains(alias.lowercase(Locale.getDefault()))) {
                    credEntry = null
                    credEntry = provider.getCredentialEntry(alias.lowercase(Locale.getDefault()))
                    pass = credEntry.credential
                    if (pass != null && pass.size > 0) {
                        credential = String(pass)
                        break
                    }
                }
            }
        } catch (ex: Exception) {
            ex.printStackTrace()
            credential = null
        }
        return credential
    }
}

测试案例:

kotlin 复制代码
import org.junit.jupiter.api.Test
class CredentialReaderTest {
    val storeType = "jceks"

    @Test
    fun testDecrypted() {
        var path: String = "D:\\projects\\CredientialReader\\src\\test\\resources\\rangeradmin.jceks"
        path=path.replace("\\","/")
        val alias: String = "unixauthtruststorealias"
        val cred = CredentialReader.getDecryptedString(path, alias, storeType)
        println(cred) 
        // success: somepassword
    }

    /**
     * method: 1, using `keytool` command!
     * [root@ranger conf]# keytool -importpass -alias ranger -storetype jceks -keystore tmp.jceks
     * Enter keystore password:
     * Re-enter new password:
     * Enter the password to be stored:
     * Re-enter password:
     * Enter key password for <ranger>
     *         (RETURN if same as keystore password):
     *
     * [root@ranger conf]# keytool -list -v -storetype jceks -keystore tmp.jceks
     * Enter keystore password:
     * Keystore type: JCEKS
     * Keystore provider: SunJCE
     *
     * Your keystore contains 1 entry
     *
     * Alias name: ranger
     * Creation date: Apr 28, 2025
     * Entry type: SecretKeyEntry
     */
    @Test
    fun testDecryptedTmp() {
    // failed : java.io.IOException: Keystore was tampered with, or password was incorrect
        var path: String = "D:\\projects\\CredientialReader\\src\\test\\resources\\tmp.jceks"
        path=path.replace("\\","/")
        val alias: String = "ranger"
        val cred = CredentialReader.getDecryptedString(path, alias, storeType)
        println(cred)
    }

    /**
     * method: 2, using `hadoop credential` command
     * hadoop credential create -help
     * hadoop credential create ranger  -value 999 -provider localjceks:///home/someone/hdp.jceks
     * hdfs hdfs -copyToLocal /home/someone/hdp.jceks .
     * Note: "localjceks://file" is fixed,"/home/someone/hdp.jceks" is real path
     * hadoop credential create ranger  -value 999 -provider localjceks://file/home/someone/hdp.jceks
     * keytool -list -v -storetype jceks -keystore hdp.jceks
     * 999
     */
    @Test
    fun testDecryptedHdp() {
    // success: 999
        var path: String = "D:\\projects\\CredientialReader\\src\\test\\resources\\hdp.jceks"
        path=path.replace("\\","/")
        val alias: String = "ranger"
        val cred = CredentialReader.getDecryptedString(path, alias, storeType)
        println(cred)
    }
}

使用keytool必须指定storepass,即jceks文件的密码。使用hadoop credential create命令生成的jceks的密码是NONE,就是没有密码。

相关推荐
不是万能的豆学长3 小时前
filetidy 文件整理助手:一键归类 + 规范重命名(Python 零依赖单文件工具)
大数据·开发语言·python·技术美术
库库的数据库笔记9 小时前
国产信创数据库的MySQL兼容性深度对比解析
大数据·数据库·mysql·oceanbase·政务
Elastic 中国社区官方博客10 小时前
我们如何通过 70 多个拉取请求,将 OpenTelemetry Java agent 迁移到 invokedynamic
java·大数据·开发语言·elasticsearch·搜索引擎·全文检索·es
珠海西格电力12 小时前
零碳园区管理系统的性能评估体系的行业标准
大数据·网络·人工智能·物联网·机器学习·架构·能源
杨先生哦12 小时前
SOC告警研判实战:海量告警降噪、误报甄别、内网风险处置全流程(上岗必用)
大数据
一线数智12 小时前
朱鹰:人的判断力,比算力更重要
大数据·人工智能
用户36105886261213 小时前
Flink ResourceManager启动流程源码深度剖析:从ClusterEntrypoint到Slot分配的完整链路
大数据
用户36105886261213 小时前
Flink ApplicationMaster启动流程源码深度剖析:从YARN提交到JobMaster启动的完整链路
大数据·flink
初心未改HD14 小时前
DSH Skill开发实战:SKILL.md是给LLM看的操作手册,不是给人看的README,踩了4个坑
java·大数据·开发语言
程序 代码狂人14 小时前
据仓库常见表类型详解(面试完整版,金融数仓适用)
大数据