You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过编程从Elytron BCFIPS凭证存储中读取密码?

问题描述

我用Bouncy Castle提供程序创建了符合FIPS 140-2标准的凭证存储,操作步骤如下:

  • 生成密钥:
    keytool -genseckey -alias key -keyalg AES -keysize 256 -keystore keystore.bcfks -storetype BCFKS -storepass myPass -keypass myPass
    
  • 通过Elytron子系统创建凭证存储:
    /subsystem=elytron/credential-store=myCredentialstore:add(relative-to=jboss.server.config.dir, credential-reference={clear-text=”${ENC::myResolver:myEncodedExpression}”}, implementation-properties={keyAlias=key, external=true, externalPath=credentialStore.bcfks, keyStoreType=BCFKS}, create=true, path=keystore.bcfks, modifiable=true)
    

当前凭证存储可正常使用,但编程读取密码时遇到问题,尝试了两种方案均失败:

方案1:使用KeyStoreCredentialStore类

能读取凭证存储中的别名,但无法获取密码,不清楚retrieve()方法的正确参数配置,代码如下:

public static Password getpassword() throws CredentialStoreException {
    Password storePassword = ClearPassword.createRaw(ClearPassword.ALGORITHM_CLEAR,
                                                     MY_CLEAR_PASSWORD.toCharArray());
    ProtectionParameter protectionParameter = new CredentialSourceProtectionParameter(IdentityCredentials.NONE.withCredential(new PasswordCredential(storePassword)));

    Provider bcProvider = new BouncyCastleFipsProvider();
    Security.addProvider(bcProvider);

    KeyStoreCredentialStore keyStoreCredentialStore = new KeyStoreCredentialStore();

    Map<String, String> kscsConfiguration = new HashMap<>();
    String keystorePath = "myPath/keystore.bcfks";
    String externalPath = "myPath/credentialStore.bcfks";

    kscsConfiguration.put("location", keystorePath);
    kscsConfiguration.put("modifiable", "true");
    kscsConfiguration.put("keyStoreType", "BCFKS");
    kscsConfiguration.put("keyAlias", "key");
    kscsConfiguration.put("external", "true");
    kscsConfiguration.put("externalPath", externalPath);

    Provider[] providers = { bcProvider };
    keyStoreCredentialStore.initialize(kscsConfiguration, protectionParameter, providers);

    PasswordCredential passwordVredential = keyStoreCredentialStore.retrieve(WEBUSER_PASSWORD_ALIAS,
                                                                             PasswordCredential.class,
                                                                             KeyStoreCredentialStore.KEY_STORE_CREDENTIAL_STORE,
                                                                             null,
                                                                             protectionParameter);
    return passwordVredential.getPassword();
}

方案2:使用ServiceContainer

调用CurrentServiceContainer.getServiceContainer()返回null,代码如下:

public static String getClientSecret(String credentialStore, String secretAlias) {
final ServiceName SERVICE_NAME_CRED_STORE = ServiceName.of("org", "wildfly", "security", "credential-store");
final ServiceName sn = ServiceName.of(SERVICE_NAME_CRED_STORE, credentialStore);
final ServiceRegistry registry = CurrentServiceContainer.getServiceContainer();
final ServiceController<?> credStoreService = registry.getService(sn);
final CredentialStore cs = (CredentialStore) credStoreService.getValue();
if (!cs.exists(secretAlias, PasswordCredential.class)) {
throw new CredentialStoreException("Alias " + secretAlias + " not found in credential store.");
}
final Password password;
try {
password = cs.retrieve(secretAlias, PasswordCredential.class).getPassword();
} catch (CredentialStoreException e) {
e.printStackTrace();
return null;
}
if (!(password instanceof ClearPassword)) {
throw new ClassCastException("Password is not of type ClearPassword");
}
return new String(((ClearPassword) password).getPassword());
}

请问如何解决上述问题,成功从该凭证存储中读取密码?


解决方案

针对方案1的修复

你的retrieve()方法参数配置有误,需调整以下几点:

  1. 简化参数:retrieve()第三个参数不需要传入KeyStoreCredentialStore.KEY_STORE_CREDENTIAL_STORE,改为null即可(表示使用默认凭证类型)。
  2. 验证密码一致性:确保protectionParameter使用的是创建凭证存储时的storepass(即代码中的MY_CLEAR_PASSWORD)。
  3. 确认别名准确性:检查WEBUSER_PASSWORD_ALIAS是否为凭证存储中实际存在的别名。

修改后的retrieve()调用代码:

PasswordCredential passwordCredential = keyStoreCredentialStore.retrieve(
    WEBUSER_PASSWORD_ALIAS,
    PasswordCredential.class,
    null,
    null,
    protectionParameter
);

额外注意事项:

  • 确认externalPath指向的credentialStore.bcfks路径正确。
  • 保证Bouncy Castle FIPS Provider版本与WildFly Elytron版本兼容,避免版本冲突导致密钥读取失败。

针对方案2的修复

CurrentServiceContainer.getServiceContainer()返回null,是因为代码未运行在WildFly容器上下文内:

  1. 运行环境限制:该方法仅在WildFly服务器内部部署的代码(如EJB、Servlet、WildFly模块)中有效,独立Java应用无法直接获取容器服务。
  2. 适配方案:
    • 若为独立应用,建议采用方案1的修复版本。
    • 若为WildFly内部应用,需将代码部署为WildFly模块或应用,并添加依赖:
      在MANIFEST.MF中添加:
      Dependencies: org.wildfly.security.elytron
      
      或在jboss-deployment-structure.xml中配置:
      <jboss-deployment-structure>
          <deployment>
              <dependencies>
                  <module name="org.wildfly.security.elytron" />
              </dependencies>
          </deployment>
      </jboss-deployment-structure>
      

额外验证步骤

  1. 用Elytron CLI命令确认目标别名存在:
    /subsystem=elytron/credential-store=myCredentialstore:read-aliases()
    
  2. 核对密钥库密码和密钥别名:确保keyAlias与生成密钥时指定的key一致,密码与storepass匹配。

内容的提问来源于stack exchange,提问作者Timea

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 21:45:38