diff --git a/backend/src/ee/services/dynamic-secret/providers/ldap.ts b/backend/src/ee/services/dynamic-secret/providers/ldap.ts
index a4c6408cb..f94e61629 100644
--- a/backend/src/ee/services/dynamic-secret/providers/ldap.ts
+++ b/backend/src/ee/services/dynamic-secret/providers/ldap.ts
@@ -7,7 +7,7 @@ import { z } from "zod";
import { BadRequestError } from "@app/lib/errors";
import { alphaNumericNanoId } from "@app/lib/nanoid";
-import { LdapSchema, TDynamicProviderFns } from "./models";
+import { LdapCredentialType, LdapSchema, TDynamicProviderFns } from "./models";
const generatePassword = () => {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~!*$#";
@@ -193,29 +193,76 @@ export const LdapProvider = (): TDynamicProviderFns => {
const providerInputs = await validateProviderInputs(inputs);
const client = await getClient(providerInputs);
- const username = generateUsername();
- const password = generatePassword();
- const generatedLdif = generateLDIF({ username, password, ldifTemplate: providerInputs.creationLdif });
+ if (providerInputs.credentialType === LdapCredentialType.Static) {
+ const dnMatch = providerInputs.rotationLdif.match(/^dn:\s*(.+)/m);
- try {
- const dnArray = await executeLdif(client, generatedLdif);
+ if (dnMatch) {
+ const username = dnMatch[1];
+ const password = generatePassword();
- return { entityId: username, data: { DN_ARRAY: dnArray, USERNAME: username, PASSWORD: password } };
- } catch (err) {
- if (providerInputs.rollbackLdif) {
- const rollbackLdif = generateLDIF({ username, password, ldifTemplate: providerInputs.rollbackLdif });
- await executeLdif(client, rollbackLdif);
+ const generatedLdif = generateLDIF({ username, password, ldifTemplate: providerInputs.rotationLdif });
+
+ try {
+ const dnArray = await executeLdif(client, generatedLdif);
+
+ return { entityId: username, data: { DN_ARRAY: dnArray, USERNAME: username, PASSWORD: password } };
+ } catch (err) {
+ throw new BadRequestError({ message: (err as Error).message });
+ }
+ } else {
+ throw new BadRequestError({
+ message: "Invalid rotation LDIF, missing DN."
+ });
+ }
+ } else {
+ const username = generateUsername();
+ const password = generatePassword();
+ const generatedLdif = generateLDIF({ username, password, ldifTemplate: providerInputs.creationLdif });
+
+ try {
+ const dnArray = await executeLdif(client, generatedLdif);
+
+ return { entityId: username, data: { DN_ARRAY: dnArray, USERNAME: username, PASSWORD: password } };
+ } catch (err) {
+ if (providerInputs.rollbackLdif) {
+ const rollbackLdif = generateLDIF({ username, password, ldifTemplate: providerInputs.rollbackLdif });
+ await executeLdif(client, rollbackLdif);
+ }
+ throw new BadRequestError({ message: (err as Error).message });
}
- throw new BadRequestError({ message: (err as Error).message });
}
};
const revoke = async (inputs: unknown, entityId: string) => {
const providerInputs = await validateProviderInputs(inputs);
- const connection = await getClient(providerInputs);
+ const client = await getClient(providerInputs);
+
+ if (providerInputs.credentialType === LdapCredentialType.Static) {
+ const dnMatch = providerInputs.rotationLdif.match(/^dn:\s*(.+)/m);
+
+ if (dnMatch) {
+ const username = dnMatch[1];
+ const password = generatePassword();
+
+ const generatedLdif = generateLDIF({ username, password, ldifTemplate: providerInputs.rotationLdif });
+
+ try {
+ const dnArray = await executeLdif(client, generatedLdif);
+
+ return { entityId: username, data: { DN_ARRAY: dnArray, USERNAME: username, PASSWORD: password } };
+ } catch (err) {
+ throw new BadRequestError({ message: (err as Error).message });
+ }
+ } else {
+ throw new BadRequestError({
+ message: "Invalid rotation LDIF, missing DN."
+ });
+ }
+ }
+
const revocationLdif = generateLDIF({ username: entityId, ldifTemplate: providerInputs.revocationLdif });
- await executeLdif(connection, revocationLdif);
+ await executeLdif(client, revocationLdif);
return { entityId };
};
diff --git a/backend/src/ee/services/dynamic-secret/providers/models.ts b/backend/src/ee/services/dynamic-secret/providers/models.ts
index c57f14477..d98215fd4 100644
--- a/backend/src/ee/services/dynamic-secret/providers/models.ts
+++ b/backend/src/ee/services/dynamic-secret/providers/models.ts
@@ -12,6 +12,11 @@ export enum ElasticSearchAuthTypes {
ApiKey = "api-key"
}
+export enum LdapCredentialType {
+ Dynamic = "dynamic",
+ Static = "static"
+}
+
export const DynamicSecretRedisDBSchema = z.object({
host: z.string().trim().toLowerCase(),
port: z.number(),
@@ -195,16 +200,26 @@ export const AzureEntraIDSchema = z.object({
clientSecret: z.string().trim().min(1)
});
-export const LdapSchema = z.object({
- url: z.string().trim().min(1),
- binddn: z.string().trim().min(1),
- bindpass: z.string().trim().min(1),
- ca: z.string().optional(),
-
- creationLdif: z.string().min(1),
- revocationLdif: z.string().min(1),
- rollbackLdif: z.string().optional()
-});
+export const LdapSchema = z.union([
+ z.object({
+ url: z.string().trim().min(1),
+ binddn: z.string().trim().min(1),
+ bindpass: z.string().trim().min(1),
+ ca: z.string().optional(),
+ credentialType: z.literal(LdapCredentialType.Dynamic).optional().default(LdapCredentialType.Dynamic),
+ creationLdif: z.string().min(1),
+ revocationLdif: z.string().min(1),
+ rollbackLdif: z.string().optional()
+ }),
+ z.object({
+ url: z.string().trim().min(1),
+ binddn: z.string().trim().min(1),
+ bindpass: z.string().trim().min(1),
+ ca: z.string().optional(),
+ credentialType: z.literal(LdapCredentialType.Static),
+ rotationLdif: z.string().min(1)
+ })
+]);
export enum DynamicSecretProviders {
SqlDatabase = "sql-database",
diff --git a/docs/documentation/platform/dynamic-secrets/ldap.mdx b/docs/documentation/platform/dynamic-secrets/ldap.mdx
index 2dc51d74e..ac06a7576 100644
--- a/docs/documentation/platform/dynamic-secrets/ldap.mdx
+++ b/docs/documentation/platform/dynamic-secrets/ldap.mdx
@@ -10,143 +10,253 @@ The Infisical LDAP dynamic secret allows you to generate user credentials on dem
1. Create a user with the necessary permissions to create users in your LDAP server.
2. Ensure your LDAP server is reachable via Infisical instance.
-## Set up Dynamic Secrets with LDAP
+## Create LDAP Credentials
-
-
- Open the Secret Overview dashboard and select the environment in which you would like to add a dynamic secret.
-
-
- 
-
-
- 
-
+
+
+
+
+ Open the Secret Overview dashboard and select the environment in which you would like to add a dynamic secret.
+
+
+ 
+
+
+ 
+
-
-
- Name by which you want the secret to be referenced
-
+
+
+ Name by which you want the secret to be referenced
+
-
- Default time-to-live for a generated secret (it is possible to modify this value when a secret is generate)
-
+
+ Default time-to-live for a generated secret (it is possible to modify this value when a secret is generate)
+
-
- Maximum time-to-live for a generated secret.
-
+
+ Maximum time-to-live for a generated secret.
+
-
- LDAP url to connect to. _(Example: ldap://your-ldap-ip:389 or ldaps://domain:636)_
-
+
+ LDAP url to connect to. _(Example: ldap://your-ldap-ip:389 or ldaps://domain:636)_
+
-
- DN to bind to. This should have permissions to create a new users.
-
+
+ DN to bind to. This should have permissions to create a new users.
+
-
- Password for the given DN.
-
+
+ Password for the given DN.
+
-
- CA certificate to use for TLS in case of a secure connection.
-
+
+ CA certificate to use for TLS in case of a secure connection.
+
-
- LDIF to run while creating a user in LDAP. This can include extra steps to assign the user to groups or set permissions.
- Here `{{Username}}`, `{{Password}}` and `{{EncodedPassword}}` are templatized variables for the username and password generated by the dynamic secret.
+
+ The type of LDAP credential - select Dynamic.
+
- `{{EncodedPassword}}` is the encoded password required for the `unicodePwd` field in Active Directory as described [here](https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/change-windows-active-directory-user-password).
+
+ LDIF to run while creating a user in LDAP. This can include extra steps to assign the user to groups or set permissions.
+ Here `{{Username}}`, `{{Password}}` and `{{EncodedPassword}}` are templatized variables for the username and password generated by the dynamic secret.
- **OpenLDAP** Example:
- ```
- dn: uid={{Username}},dc=infisical,dc=com
- changetype: add
- objectClass: top
- objectClass: person
- objectClass: organizationalPerson
- objectClass: inetOrgPerson
- cn: John Doe
- sn: Doe
- uid: jdoe
- mail: jdoe@infisical.com
- userPassword: {{Password}}
- ```
+ `{{EncodedPassword}}` is the encoded password required for the `unicodePwd` field in Active Directory as described [here](https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/change-windows-active-directory-user-password).
- **Active Directory** Example:
- ```
- dn: CN={{Username}},OU=Test Create,DC=infisical,DC=com
- changetype: add
- objectClass: top
- objectClass: person
- objectClass: organizationalPerson
- objectClass: user
- userPrincipalName: {{Username}}@infisical.com
- sAMAccountName: {{Username}}
- unicodePwd::{{EncodedPassword}}
- userAccountControl: 66048
+ **OpenLDAP** Example:
+ ```
+ dn: uid={{Username}},dc=infisical,dc=com
+ changetype: add
+ objectClass: top
+ objectClass: person
+ objectClass: organizationalPerson
+ objectClass: inetOrgPerson
+ cn: John Doe
+ sn: Doe
+ uid: jdoe
+ mail: jdoe@infisical.com
+ userPassword: {{Password}}
+ ```
- dn: CN=test-group,OU=Test Create,DC=infisical,DC=com
- changetype: modify
- add: member
- member: CN={{Username}},OU=Test Create,DC=infisical,DC=com
- -
- ```
-
+ **Active Directory** Example:
+ ```
+ dn: CN={{Username}},OU=Test Create,DC=infisical,DC=com
+ changetype: add
+ objectClass: top
+ objectClass: person
+ objectClass: organizationalPerson
+ objectClass: user
+ userPrincipalName: {{Username}}@infisical.com
+ sAMAccountName: {{Username}}
+ unicodePwd::{{EncodedPassword}}
+ userAccountControl: 66048
-
- LDIF to run while revoking a user in LDAP. This can include extra steps to remove the user from groups or set permissions.
- Here `{{Username}}` is a templatized variable for the username generated by the dynamic secret.
+ dn: CN=test-group,OU=Test Create,DC=infisical,DC=com
+ changetype: modify
+ add: member
+ member: CN={{Username}},OU=Test Create,DC=infisical,DC=com
+ -
+ ```
+
- **OpenLDAP / Active Directory** Example:
- ```
- dn: CN={{Username}},OU=Test Create,DC=infisical,DC=com
- changetype: delete
- ```
-
+
+ LDIF to run while revoking a user in LDAP. This can include extra steps to remove the user from groups or set permissions.
+ Here `{{Username}}` is a templatized variable for the username generated by the dynamic secret.
-
- LDIF to run incase Creation LDIF fails midway.
+ **OpenLDAP / Active Directory** Example:
+ ```
+ dn: CN={{Username}},OU=Test Create,DC=infisical,DC=com
+ changetype: delete
+ ```
+
- For the creation example shown above, if the user is created successfully but not added to a group, this LDIF can be used to remove the user.
- Here `{{Username}}`, `{{Password}}` and `{{EncodedPassword}}` are templatized variables for the username generated by the dynamic secret.
+
+ LDIF to run incase Creation LDIF fails midway.
- **OpenLDAP / Active Directory** Example:
- ```
- dn: CN={{Username}},OU=Test Create,DC=infisical,DC=com
- changetype: delete
- ```
-
+ For the creation example shown above, if the user is created successfully but not added to a group, this LDIF can be used to remove the user.
+ Here `{{Username}}`, `{{Password}}` and `{{EncodedPassword}}` are templatized variables for the username generated by the dynamic secret.
-
+ **OpenLDAP / Active Directory** Example:
+ ```
+ dn: CN={{Username}},OU=Test Create,DC=infisical,DC=com
+ changetype: delete
+ ```
+
+
-
- After submitting the form, you will see a dynamic secret created in the dashboard.
-
-
- Once you've successfully configured the dynamic secret, you're ready to generate on-demand credentials.
- To do this, simply click on the 'Generate' button which appears when hovering over the dynamic secret item.
- Alternatively, you can initiate the creation of a new lease by selecting 'New Lease' from the dynamic secret lease list section.
+
+ After submitting the form, you will see a dynamic secret created in the dashboard.
+
+
+ Once you've successfully configured the dynamic secret, you're ready to generate on-demand credentials.
+ To do this, simply click on the 'Generate' button which appears when hovering over the dynamic secret item.
+ Alternatively, you can initiate the creation of a new lease by selecting 'New Lease' from the dynamic secret lease list section.
- 
- 
+ 
+ 
- When generating these secrets, it's important to specify a Time-to-Live (TTL) duration. This will dictate how long the credentials are valid for.
+ When generating these secrets, it's important to specify a Time-to-Live (TTL) duration. This will dictate how long the credentials are valid for.
- 
+ 
-
- Ensure that the TTL for the lease fall within the maximum TTL defined when configuring the dynamic secret.
-
+
+ Ensure that the TTL for the lease fall within the maximum TTL defined when configuring the dynamic secret.
+
- Once you click the `Submit` button, a new secret lease will be generated and the credentials from it will be shown to you with an array of DN's altered depending on the Creation LDIF.
+ Once you click the `Submit` button, a new secret lease will be generated and the credentials from it will be shown to you with an array of DN's altered depending on the Creation LDIF.
- 
+ 
+
-
+
-
+
+
+
+
+ Open the Secret Overview dashboard and select the environment in which you would like to add a dynamic secret.
+
+
+ 
+
+
+ 
+
+
+
+
+ Name by which you want the secret to be referenced
+
+
+
+ Default time-to-live for a generated secret (it is possible to modify this value when a secret is generate)
+
+
+
+ Maximum time-to-live for a generated secret.
+
+
+
+ LDAP url to connect to. _(Example: ldap://your-ldap-ip:389 or ldaps://domain:636)_
+
+
+
+ DN to bind to. This should have permissions to create a new users.
+
+
+
+ Password for the given DN.
+
+
+
+ CA certificate to use for TLS in case of a secure connection.
+
+
+
+ The type of LDAP credential - select Static.
+
+
+
+ LDIF to run for rotating the credentals of an LDAP user. This can include extra LDAP steps based on your needs.
+ Here `{{Password}}` and `{{EncodedPassword}}` are templatized variables for the password generated by the dynamic secret.
+
+ Note that the `-` characters and the empty lines found at the end of the examples are necessary based on the LDIF format.
+
+ **OpenLDAP** Example:
+ ```
+ dn: cn=sheencaps capadngan,ou=people,dc=acme,dc=com
+ changetype: modify
+ replace: userPassword
+ password: {{Password}}
+ -
+
+ ```
+
+ **Active Directory** Example:
+ ```
+ dn: cn=sheencaps capadngan,ou=people,dc=acme,dc=com
+ changetype: modify
+ replace: unicodePwd
+ unicodePwd::{{EncodedPassword}}
+ -
+
+ ```
+ `{{EncodedPassword}}` is the encoded password required for the `unicodePwd` field in Active Directory as described [here](https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/change-windows-active-directory-user-password).
+
+
+
+
+
+ After submitting the form, you will see a dynamic secret created in the dashboard.
+
+
+ Once you've successfully configured the dynamic secret, you're ready to generate on-demand credentials.
+ To do this, simply click on the 'Generate' button which appears when hovering over the dynamic secret item.
+ Alternatively, you can initiate the creation of a new lease by selecting 'New Lease' from the dynamic secret lease list section.
+
+ 
+ 
+
+ When generating these secrets, it's important to specify a Time-to-Live (TTL) duration. This will dictate how long the credentials are valid for.
+
+ 
+
+
+ Ensure that the TTL for the lease fall within the maximum TTL defined when configuring the dynamic secret.
+
+
+
+ Once you click the `Submit` button, a new secret lease will be generated and the credentials from it will be shown to you with an array of DN's altered depending on the Creation LDIF.
+
+ 
+
+
+
+
+
+
## Active Directory Integration
diff --git a/frontend/src/hooks/api/dynamicSecret/types.ts b/frontend/src/hooks/api/dynamicSecret/types.ts
index 4f2a787b9..7ac8d4147 100644
--- a/frontend/src/hooks/api/dynamicSecret/types.ts
+++ b/frontend/src/hooks/api/dynamicSecret/types.ts
@@ -199,9 +199,11 @@ export type TDynamicSecretProvider =
binddn: string;
bindpass: string;
ca?: string | undefined;
- creationLdif: string;
- revocationLdif: string;
+ credentialType: string;
+ creationLdif?: string;
+ revocationLdif?: string;
rollbackLdif?: string;
+ rotationLdif?: string;
};
}
| {
diff --git a/frontend/src/views/SecretMainPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx b/frontend/src/views/SecretMainPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx
index b78161aa5..1a7e0e8fa 100644
--- a/frontend/src/views/SecretMainPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx
+++ b/frontend/src/views/SecretMainPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx
@@ -8,21 +8,47 @@ import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
-import { Button, FormControl, Input, TextArea } from "@app/components/v2";
+import { Button, FormControl, Input, Select, SelectItem, TextArea } from "@app/components/v2";
import { useCreateDynamicSecret } from "@app/hooks/api";
import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types";
-const formSchema = z.object({
- provider: z.object({
- url: z.string().trim().min(1),
- binddn: z.string().trim().min(1),
- bindpass: z.string().trim().min(1),
- ca: z.string().optional(),
+enum CredentialType {
+ Dynamic = "dynamic",
+ Static = "static"
+}
- creationLdif: z.string().min(1),
- revocationLdif: z.string().min(1),
- rollbackLdif: z.string().optional()
- }),
+const credentialTypes = [
+ {
+ label: "Dynamic",
+ value: CredentialType.Dynamic
+ },
+ {
+ label: "Static",
+ value: CredentialType.Static
+ }
+] as const;
+
+const formSchema = z.object({
+ provider: z.discriminatedUnion("credentialType", [
+ z.object({
+ url: z.string().trim().min(1),
+ binddn: z.string().trim().min(1),
+ bindpass: z.string().trim().min(1),
+ ca: z.string().optional(),
+ credentialType: z.literal(CredentialType.Dynamic),
+ creationLdif: z.string().min(1),
+ revocationLdif: z.string().min(1),
+ rollbackLdif: z.string().optional()
+ }),
+ z.object({
+ url: z.string().trim().min(1),
+ binddn: z.string().trim().min(1),
+ bindpass: z.string().trim().min(1),
+ ca: z.string().optional(),
+ credentialType: z.literal(CredentialType.Static),
+ rotationLdif: z.string().min(1)
+ })
+ ]),
defaultTTL: z.string().superRefine((val, ctx) => {
const valMs = ms(val);
@@ -67,6 +93,8 @@ export const LdapInputForm = ({
const {
control,
formState: { isSubmitting },
+ setValue,
+ watch,
handleSubmit
} = useForm({
resolver: zodResolver(formSchema),
@@ -78,11 +106,14 @@ export const LdapInputForm = ({
ca: "",
creationLdif: "",
revocationLdif: "",
- rollbackLdif: ""
+ rollbackLdif: "",
+ credentialType: CredentialType.Dynamic
}
}
});
+ const selectedCredentialType = watch("provider.credentialType");
+
const createDynamicSecret = useCreateDynamicSecret();
const handleCreateDynamicSecret = async ({ name, maxTTL, provider, defaultTTL }: TForm) => {
@@ -240,45 +271,106 @@ export const LdapInputForm = ({
(
-
+
)}
/>
- (
-
-
-
- )}
- />
+ {selectedCredentialType === CredentialType.Dynamic && (
+ <>
+ (
+
+
+
+ )}
+ />
- (
-
-
-
- )}
- />
+ (
+
+
+
+ )}
+ />
+
+ (
+
+
+
+ )}
+ />
+ >
+ )}
+ {selectedCredentialType === CredentialType.Static && (
+ (
+
+
+
+ )}
+ />
+ )}
diff --git a/frontend/src/views/SecretMainPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretLdapForm.tsx b/frontend/src/views/SecretMainPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretLdapForm.tsx
index 5d0b5938f..0cbad664a 100644
--- a/frontend/src/views/SecretMainPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretLdapForm.tsx
+++ b/frontend/src/views/SecretMainPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretLdapForm.tsx
@@ -5,22 +5,47 @@ import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
-import { Button, FormControl, Input, TextArea } from "@app/components/v2";
+import { Button, FormControl, Input, Select, SelectItem, TextArea } from "@app/components/v2";
import { useUpdateDynamicSecret } from "@app/hooks/api";
import { TDynamicSecret } from "@app/hooks/api/dynamicSecret/types";
+enum CredentialType {
+ Dynamic = "dynamic",
+ Static = "static"
+}
+
+const credentialTypes = [
+ {
+ label: "Dynamic",
+ value: CredentialType.Dynamic
+ },
+ {
+ label: "Static",
+ value: CredentialType.Static
+ }
+] as const;
+
const formSchema = z.object({
- inputs: z
- .object({
+ inputs: z.discriminatedUnion("credentialType", [
+ z.object({
url: z.string().trim().min(1),
binddn: z.string().trim().min(1),
bindpass: z.string().trim().min(1),
ca: z.string().optional(),
+ credentialType: z.literal(CredentialType.Dynamic),
creationLdif: z.string().min(1),
revocationLdif: z.string().min(1),
rollbackLdif: z.string().optional()
+ }),
+ z.object({
+ url: z.string().trim().min(1),
+ binddn: z.string().trim().min(1),
+ bindpass: z.string().trim().min(1),
+ ca: z.string().optional(),
+ credentialType: z.literal(CredentialType.Static),
+ rotationLdif: z.string().min(1)
})
- .partial(),
+ ]),
defaultTTL: z.string().superRefine((val, ctx) => {
const valMs = ms(val);
if (valMs < 60 * 1000)
@@ -67,7 +92,9 @@ export const EditDynamicSecretLdapForm = ({
const {
control,
formState: { isSubmitting },
- handleSubmit
+ handleSubmit,
+ watch,
+ setValue
} = useForm({
resolver: zodResolver(formSchema),
values: {
@@ -81,6 +108,7 @@ export const EditDynamicSecretLdapForm = ({
});
const updateDynamicSecret = useUpdateDynamicSecret();
+ const selectedCredentialType = watch("inputs.credentialType");
const handleUpdateDynamicSecret = async ({ inputs, maxTTL, defaultTTL, newName }: TForm) => {
// wait till previous request is finished
@@ -204,43 +232,103 @@ export const EditDynamicSecretLdapForm = ({
/>
(
-
-
- )}
- />
- (
-
-
-
- )}
- />
- (
-
-
+
)}
/>
+ {selectedCredentialType === CredentialType.Dynamic && (
+ <>
+ (
+
+
+
+ )}
+ />
+ (
+
+
+
+ )}
+ />
+ (
+
+
+
+ )}
+ />
+ >
+ )}
+ {selectedCredentialType === CredentialType.Static && (
+ (
+
+
+
+ )}
+ />
+ )}