【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,就是没有密码。

相关推荐
笨蛋不要掉眼泪5 小时前
RabbitMQ消息队列:交换机机制
java·分布式·rabbitmq
zcmodeltech5 小时前
智慧农业沙盘模型物联网控制系统设计:基于STM32与Modbus RTU的传感器-执行器闭环方案
服务器·分布式·stm32·嵌入式硬件·物联网·能源
想你依然心痛5 小时前
HarmonyOS 5.0智慧农业开发实战:构建分布式农业物联网与区块链农产品溯源系统
人工智能·分布式·物联网·区块链·智慧农业·harmonyos·开发实战
spider_xcxc17 小时前
Argo CD App of Apps 模式深度解析:像管理应用一样管理应用
大数据·数据库·elasticsearch
珠***格18 小时前
分布式光伏电站:四可装置如何实现 “可观、可测、可控、可调”
网络·人工智能·分布式·架构·能源
奥莱维18 小时前
酒店客房智能控制如何提升睡眠与入住体验
大数据·人工智能
greenbbLV19 小时前
中小公司积分商城选型:SaaS与私有化优劣对比分析
大数据·运维·人工智能
希艾席帝恩20 小时前
数字孪生赋能智慧物流:物流行业转型升级新路径
大数据·人工智能·低代码·ai·数字化转型
L16247620 小时前
消息队列(MQ)总览:RabbitMQ & Kafka 完整手册
分布式·kafka·rabbitmq
阿里云大数据AI技术20 小时前
EMR Serverless Spark 基于 MinHash-LSH 实现 PB 级文本语义去重 4 倍加速
大数据·人工智能·spark