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