jenkinsci / jenkinsci/credentials-plugin
CredentialsParameterDefinition concrete-class filtering excludes proxy-backed external credentials
- Dominant language
- Java
- Stars
- 134
- Forks
- 258
- Avg merge
- 48m
- Merged PRs (30d)
- 1
Description
### Jenkins and plugins versions report
Environment
```text
Jenkins: 2.568.2
OS: Linux - 7.1.10-200.fc44.x86_64
Java: 21.0.12 - Eclipse Adoptium (OpenJDK 64-Bit Server VM)
---
antisamy-markup-formatter:173.v680e3a_b_69ff3
apache-httpcomponents-client-4-api:4.5.14-269.vfa_2321039a_83
asm-api:9.10.1-216.va_9256d3b_844b_
bitwarden-credentials-provider:400.vb_e8b_72889291
bootstrap5-api:5.3.8-1048.va_c299057e35c
bouncycastle-api:2.30.1.84-291.v9f17b_21896e2
branch-api:2.1280.v0d4e5b_b_460ef
caffeine-api:3.2.4-208.v7e2da_a_7db_82b_
cloudbees-folder:6.1106.v3a_d9a_6d2465e
commons-lang3-api:3.20.0-109.ve43756e2d2b_4
commons-text-api:1.15.0-218.va_61573470393
configuration-as-code:2117.vc05a_0b_e6b_f4e
credentials:1511.v2e3cb_0008ef0
credentials-binding:728.v902a_273b_8947
dark-theme:652.vea_da_dfea_e769
display-url-api:2.217.va_6b_de84cc74b_
durable-task:686.v80ff80875b_82
font-awesome-api:7.3.1-1013.v0835a_879ec6d
instance-identity:203.v15e81a_1b_7a_38
ionicons-api:94.vcc3065403257
jackson-annotations2-api:2.22-19.v10a_a_582ea_26e
jackson2-api:2.22.2-445.vdc613f1d8012
jackson3-api:3.2.2-96.v599957900a_1a_
jakarta-activation-api:2.1.4-1
jakarta-mail-api:2.1.5-1
jakarta-xml-bind-api:4.0.9-19.v2b_a_5b_44d9a_1c
javax-activation-api:1.2.0-8
jaxb:2.3.9-143.v5979df3304e6
joda-time-api:2.14.3-200.v65623733c99f
json-api:20260814-226.v20f9685d642c
mailer:534.v1b_36f5864073
matrix-auth:3.3
pipeline-build-step:599.v4b_67ea_11b_152
pipeline-groovy-lib:798.v5cc688825312
pipeline-input-step:560.v56198a_642157
pipeline-milestone-step:152.v6e22b_8cfc66c
pipeline-model-api:2.2293.v6e7193cec599
pipeline-model-definition:2.2291.v2934911987b_6
pipeline-model-extensions:2.2291.v2934911987b_6
pipeline-stage-step:345.va_96187909426
pipeline-stage-tags-metadata:2.2293.v6e7193cec599
plain-credentials:199.v9f8e1f741799
plugin-util-api:7.1341.v039f146993d9
prism-api:1.30.0-741.v034eb_0b_0a_a_fa_
scm-api:728.vc30dcf7a_0df5
script-security:1412.v7737b_3405f86
snakeyaml-api:2.5-149.v72471e9c6371
snakeyaml-engine-api:3.1.1-12.v4320c7d6f89c
ssh-credentials:372.va_250881b_08cd
structs:362.va_b_695ef4fdf9
theme-manager:346.v06cca_64c6a_37
variant:70.va_d9f17f859e0
woodstox-core-api:7.2.2-10.vcb_629759b_2c2
workflow-aggregator:608.v67378e9d3db_1
workflow-api:1413.v2ff1a_5e720fa_
workflow-basic-steps:1098.v808b_fd7f8cf4
workflow-cps:4370.v49a_6937566b_6
workflow-durable-task-step:1479.v56e587f413a_7
workflow-job:1590.v49101d088542
workflow-multibranch:841.vec5b_9e1806ec
workflow-scm-step:466.va_d69e602552b_
workflow-step-api:724.v538c2362b_dfb_
workflow-support:1015.v785e5a_b_b_8b_22
```
### What Operating System are you using (both controller, and any agents involved in the problem)?
Controller: Fedora 44 Linux - 7.1.10-200.fc44.x86_64
The issue occurs while Jenkins populates a credentials parameter dropdown on the controller. No agent is involved. Based on the behavior described below, it appears independent of the controller operating system and Java version.
### Reproduction steps
1. Install the Credentials and Bitwarden Credentials Provider plugins.
2. Configure the Bitwarden provider plugin with a Bitwarden vault containing at least one Secure Note.
3. Confirm that the Secure Note:
- Appears in the Bitwarden credential store as a Secret text credential
- Can be resolved successfully as `StringCredentials`, for example using `withCredentials`
4. Create a Pipeline job with a Credentials Parameter.
5. Set the parameter's **Credential type** to **Secret text**.
6. Inspect the parameter's **Default Value** dropdown or open **Build with Parameters**.
7. Observe that the Java dynamic proxy-backed Bitwarden Secret text credential is absent from the list:
8. Edit the parameter and change **Credential type** to **Any**.
9. Inspect the dropdown again.
10. Observe that the same Bitwarden credential is now present and selectable:
The same behavior applies to the other proxied credential types exposed by the provider, including username/password, secret file, and SSH private key credentials. A single Secret text reproduction is sufficient to demonstrate the underlying issue.
### Expected Results
When **Credential type** is set to **Secret text**, the dropdown should include Java dynamic proxy-backed credentials representing that credential type.
The Bitwarden credential in the above example:
- Implements the public `StringCredentials` interface
- Therefore also implements `StandardCredentials` and `Credentials`
- Returns the official `StringCredentialsImpl` descriptor from `getDescriptor()`
- Lazily delegates secret access to an official `StringCredentialsImpl` instance
It should therefore be recognized as a Secret text credential.
Type filtering should not require an external provider's proxied credential objects to extend Jenkins concrete credential implementation classes.
### Actual Results
The proxy-backed credential is omitted from the credential parameter dropdown when **Credential type** is set to **Secret text**.
The same credential appears and is selectable when **Credential type** is changed to **Any**.
No relevant errors or warnings are logged.
### Anything else?
#### Suspected cause
`CredentialsParameterDefinition.DescriptorImpl.doFillCredentialTypeItems()` populates the type selector using: `descriptor.clazz.getName()`
For Secret text, this stores the concrete implementation class name: `org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl`
`CredentialsParameterDefinition.DescriptorImpl.decodeType()` resolves that value back to the concrete implementation class. `doFillDefaultValueItems()` / `doFillValueItems()` pass it to `StandardListBoxModel.includeAs(...)`. The resulting lookup therefore requests `StringCredentialsImpl.class`.
A Java dynamic proxy implementing `StringCredentials` is correctly an instance of:
- `StringCredentials`
- `StandardCredentials`
- `Credentials`
It cannot be an instance of the concrete class `StringCredentialsImpl`.
The Bitwarden provider plugin honors requests for a specific credential type using: `.filter(type::isInstance)`.
Consequently, the proxied credential is excluded when the credential parameter requests `StringCredentialsImpl.class`, even though the proxy implements the corresponding public API interfaces and returns the official implementation descriptor.
It seems that instead, the credential parameter should request the secret text _interface_: `StringCredentials`.
For reference, the affected relevant downstream proxy and credential filtering implementations can be found here:
- https://github.com/jenkinsci/bitwarden-credentials-provider-plugin/blob/main/src/main/java/com/mwdle/bitwarden/converters/CredentialProxy.java
- https://github.com/jenkinsci/bitwarden-credentials-provider-plugin/blob/31c155eaf5782848c370ac323f163e40c63c3b51/src/main/java/com/mwdle/bitwarden/BitwardenCredentialsProvider.java#L57
#### Conflict with the Credentials API provider model
The Credentials plugin implementation guide explicitly recommends lazy `java.lang.reflect.Proxy` credentials for providers backed by external stores. It also explains that credential consumers should depend on the public credential interfaces and must not assume that credentials use a particular default implementation class: https://github.com/jenkinsci/credentials-plugin/blob/master/docs/implementation.adoc
`CredentialsParameterDefinition` currently derives its filter from `CredentialsDescriptor.clazz` and then requires the returned credential object to be an instance of that concrete class. This excludes the proxy-based provider model recommended by the same implementation guide.
#### Current workaround
Selecting **Any**, or omitting `credentialType` from a Pipeline credential parameter definition, causes the lookup to use `StandardCredentials`, and thus the proxy-backed credentials appear.
This workaround removes useful type filtering and causes the dropdown to contain credentials of every type.
### Are you interested in contributing a fix?
I maintain the downstream Bitwarden Credentials Provider plugin and can help test and validate a proposed fix against it. I am not currently planning to contribute the upstream implementation.
Contributor guide
Assessment
This issue has not been assessed yet.