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

相关推荐
SelectDB2 小时前
森马服饰从 Elasticsearch 到阿里云 SelectDB 的架构演进之路
大数据·数据库·数据分析
Hello.Reader2 小时前
Elasticsearch 混合检索一句 `retriever.rrf`,把语义召回与关键词召回融合到极致
大数据·elasticsearch·搜索引擎
Freed&2 小时前
倒排索引:Elasticsearch 搜索背后的底层原理
大数据·elasticsearch·搜索引擎·lucene
bemyrunningdog2 小时前
IntelliJIDEA上传GitHub全攻略
大数据·elasticsearch·搜索引擎
小傅哥4 小时前
【分享】拼团交易平台系统,分布式、高并发、微服务
分布式·微服务·状态模式
九河云4 小时前
电商直播流量爆发式增长,华为云分布式流量治理与算力调度服务的应用场景剖析
分布式·科技·华为云·电商·传统
TDengine (老段)6 小时前
TDengine 中 TDgp 中添加算法模型(异常检测)
java·大数据·数据库·算法·时序数据库·tdengine·涛思数据
2501_924748247 小时前
高密度客流识别精度↑32%!陌讯多模态融合算法在智慧交通的实战解析
大数据·人工智能·算法·目标检测·计算机视觉
腾讯云qcloud07557 小时前
不办理腾讯地图商业授权有什么影响?
大数据
归梧谣8 小时前
部署Zabbix企业级分布式监控
分布式·zabbix