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

相关推荐
MZWeiei10 分钟前
Spark on YARN 的运行架构总览
大数据·架构·spark
数据要素X12 分钟前
【数据架构07】数据智能架构篇
大数据·数据库·数据仓库·人工智能·架构
敖云岚17 分钟前
【Hadoop】大数据技术之 MapReduce
大数据·hadoop·mapreduce
吾日三省吾码33 分钟前
ZooKeeper 原理解析及优劣比较
分布式·zookeeper·云原生
搞不懂语言的程序员2 小时前
如何保证 Kafka 数据实时同步到 Elasticsearch?
分布式·elasticsearch·kafka
Dust | 棉花糖2 小时前
云原生+大数据
java·大数据·云原生
酷柚易汛4 小时前
酷柚易汛ERP标签打印解决方案
大数据·微信小程序·erp
不爱学英文的码字机器4 小时前
[Git] 如何进行版本回退
大数据·git·elasticsearch
李景琰4 小时前
分布式事务之Seata
java·分布式
MZWeiei5 小时前
Spark 中,创建 DataFrame 的方式(Scala语言)
大数据·分布式·spark·scala