parent
990a54dce5
commit
21a23ace1d
25 changed files with 113 additions and 16 deletions
|
@ -31,6 +31,7 @@ public class ConfigPropertyRepresentation {
|
|||
protected Object defaultValue;
|
||||
protected List<String> options;
|
||||
protected boolean secret;
|
||||
protected boolean required;
|
||||
private boolean readOnly;
|
||||
|
||||
public String getName() {
|
||||
|
@ -89,6 +90,14 @@ public class ConfigPropertyRepresentation {
|
|||
this.secret = secret;
|
||||
}
|
||||
|
||||
public boolean isRequired() {
|
||||
return required;
|
||||
}
|
||||
|
||||
public void setRequired(boolean required) {
|
||||
this.required = required;
|
||||
}
|
||||
|
||||
public void setReadOnly(boolean readOnly) {
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
|
|
|
@ -77,6 +77,12 @@ public abstract class AbstractLDAPStorageMapperFactory implements LDAPStorageMap
|
|||
return configProperty;
|
||||
}
|
||||
|
||||
public static ProviderConfigProperty createConfigProperty(String name, String label, String helpText, String type, List<String> options, boolean required) {
|
||||
ProviderConfigProperty property = createConfigProperty(name, label, helpText, type, options);
|
||||
property.setRequired(required);
|
||||
return property;
|
||||
}
|
||||
|
||||
protected void checkMandatoryConfigAttribute(String name, String displayName, ComponentModel mapperModel) throws ComponentValidationException {
|
||||
String attrConfigValue = mapperModel.getConfig().getFirst(name);
|
||||
if (attrConfigValue == null || attrConfigValue.trim().isEmpty()) {
|
||||
|
|
|
@ -36,13 +36,19 @@ public class HardcodedAttributeMapperFactory extends AbstractLDAPStorageMapperFa
|
|||
protected static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||
|
||||
static {
|
||||
ProviderConfigProperty attrName = createConfigProperty(HardcodedAttributeMapper.USER_MODEL_ATTRIBUTE, "User Model Attribute Name",
|
||||
ProviderConfigProperty attrName = createConfigProperty(HardcodedAttributeMapper.USER_MODEL_ATTRIBUTE,
|
||||
"User Model Attribute Name",
|
||||
"Name of the model attribute, which will be added when importing user from ldap",
|
||||
ProviderConfigProperty.STRING_TYPE, null);
|
||||
ProviderConfigProperty.STRING_TYPE,
|
||||
null,
|
||||
true);
|
||||
|
||||
ProviderConfigProperty attrValue = createConfigProperty(HardcodedAttributeMapper.ATTRIBUTE_VALUE, "Attribute Value",
|
||||
ProviderConfigProperty attrValue = createConfigProperty(HardcodedAttributeMapper.ATTRIBUTE_VALUE,
|
||||
"Attribute Value",
|
||||
"Value of the model attribute, which will be added when importing user from ldap.",
|
||||
ProviderConfigProperty.STRING_TYPE, null);
|
||||
ProviderConfigProperty.STRING_TYPE,
|
||||
null,
|
||||
true);
|
||||
|
||||
configProperties.add(attrName);
|
||||
configProperties.add(attrValue);
|
||||
|
|
|
@ -38,14 +38,20 @@ public class HardcodedLDAPAttributeMapperFactory extends AbstractLDAPStorageMapp
|
|||
protected static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||
|
||||
static {
|
||||
ProviderConfigProperty attrName = createConfigProperty(HardcodedLDAPAttributeMapper.LDAP_ATTRIBUTE_NAME, "LDAP Attribute Name",
|
||||
ProviderConfigProperty attrName = createConfigProperty(HardcodedLDAPAttributeMapper.LDAP_ATTRIBUTE_NAME,
|
||||
"LDAP Attribute Name",
|
||||
"Name of the LDAP attribute, which will be added to the new user during registration",
|
||||
ProviderConfigProperty.STRING_TYPE, null);
|
||||
ProviderConfigProperty.STRING_TYPE,
|
||||
null,
|
||||
true);
|
||||
|
||||
ProviderConfigProperty attrValue = createConfigProperty(HardcodedLDAPAttributeMapper.LDAP_ATTRIBUTE_VALUE, "LDAP Attribute Value",
|
||||
ProviderConfigProperty attrValue = createConfigProperty(HardcodedLDAPAttributeMapper.LDAP_ATTRIBUTE_VALUE,
|
||||
"LDAP Attribute Value",
|
||||
"Value of the LDAP attribute, which will be added to the new user during registration. You can either hardcode any value like 'foo' but you can also use some special tokens. "
|
||||
+ "Only supported token right now is '${RANDOM}' , which will be replaced with some randomly generated String.",
|
||||
ProviderConfigProperty.STRING_TYPE, null);
|
||||
ProviderConfigProperty.STRING_TYPE,
|
||||
null,
|
||||
true);
|
||||
|
||||
configProperties.add(attrName);
|
||||
configProperties.add(attrValue);
|
||||
|
|
|
@ -38,9 +38,12 @@ public class HardcodedLDAPGroupStorageMapperFactory extends AbstractLDAPStorageM
|
|||
protected static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||
|
||||
static {
|
||||
ProviderConfigProperty groupAttr = createConfigProperty(HardcodedLDAPGroupStorageMapper.GROUP, "Group",
|
||||
ProviderConfigProperty groupAttr = createConfigProperty(HardcodedLDAPGroupStorageMapper.GROUP,
|
||||
"Group",
|
||||
"Group to add the user in. Fill the full path of the group including path. For example '/root-group/child-group'",
|
||||
ProviderConfigProperty.STRING_TYPE, null);
|
||||
ProviderConfigProperty.STRING_TYPE,
|
||||
null,
|
||||
true);
|
||||
|
||||
configProperties.add(groupAttr);
|
||||
}
|
||||
|
|
|
@ -38,9 +38,12 @@ public class HardcodedLDAPRoleStorageMapperFactory extends AbstractLDAPStorageMa
|
|||
protected static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||
|
||||
static {
|
||||
ProviderConfigProperty roleAttr = createConfigProperty(HardcodedLDAPRoleStorageMapper.ROLE, "Role",
|
||||
ProviderConfigProperty roleAttr = createConfigProperty(HardcodedLDAPRoleStorageMapper.ROLE,
|
||||
"Role",
|
||||
"Role to grant to user. Click 'Select Role' button to browse roles, or just type it in the textbox. To reference a client role the syntax is clientname.clientrole, i.e. myclient.myrole",
|
||||
ProviderConfigProperty.ROLE_TYPE, null);
|
||||
ProviderConfigProperty.ROLE_TYPE,
|
||||
null,
|
||||
true);
|
||||
configProperties.add(roleAttr);
|
||||
}
|
||||
|
||||
|
|
|
@ -56,9 +56,11 @@ public class UserAttributeLDAPStorageMapperFactory extends AbstractLDAPStorageMa
|
|||
.label("User Model Attribute")
|
||||
.helpText("Name of the UserModel property or attribute you want to map the LDAP attribute into. For example 'firstName', 'lastName, 'email', 'street' etc.")
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.required(true)
|
||||
.add()
|
||||
.property().name(UserAttributeLDAPStorageMapper.LDAP_ATTRIBUTE).label("LDAP Attribute").helpText("Name of mapped attribute on LDAP object. For example 'cn', 'sn, 'mail', 'street' etc.")
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.required(true)
|
||||
.add()
|
||||
.property().name(UserAttributeLDAPStorageMapper.READ_ONLY).label("Read Only")
|
||||
.helpText("Read-only attribute is imported from LDAP to UserModel, but it's not saved back to LDAP when user is updated in Keycloak.")
|
||||
|
|
|
@ -96,6 +96,7 @@ public class GroupLDAPStorageMapperFactory extends AbstractLDAPStorageMapperFact
|
|||
.label("LDAP Groups DN")
|
||||
.helpText("LDAP DN where are groups of this tree saved. For example 'ou=groups,dc=example,dc=org' ")
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.required(true)
|
||||
.add()
|
||||
.property().name(GroupMapperConfig.GROUP_NAME_LDAP_ATTRIBUTE)
|
||||
.label("Group Name LDAP Attribute")
|
||||
|
|
|
@ -94,6 +94,7 @@ public class RoleLDAPStorageMapperFactory extends AbstractLDAPStorageMapperFacto
|
|||
.label("LDAP Roles DN")
|
||||
.helpText("LDAP DN where are roles of this tree saved. For example 'ou=finance,dc=example,dc=org' ")
|
||||
.type(ProviderConfigProperty.STRING_TYPE)
|
||||
.required(true)
|
||||
.add()
|
||||
.property().name(RoleMapperConfig.ROLE_NAME_LDAP_ATTRIBUTE)
|
||||
.label("Role Name LDAP Attribute")
|
||||
|
|
|
@ -17,7 +17,6 @@ import type { ComponentProps } from "../dynamic/components";
|
|||
|
||||
type ClientSelectProps = ComponentProps & {
|
||||
namespace: string;
|
||||
required?: boolean;
|
||||
};
|
||||
|
||||
export const ClientSelect = ({
|
||||
|
|
|
@ -15,7 +15,12 @@ import { HelpItem } from "ui-shared";
|
|||
import type { ComponentProps } from "./components";
|
||||
import { convertToName } from "./DynamicComponents";
|
||||
|
||||
export const GroupComponent = ({ name, label, helpText }: ComponentProps) => {
|
||||
export const GroupComponent = ({
|
||||
name,
|
||||
label,
|
||||
helpText,
|
||||
required,
|
||||
}: ComponentProps) => {
|
||||
const { t } = useTranslation();
|
||||
const [open, setOpen] = useState(false);
|
||||
const [groups, setGroups] = useState<GroupRepresentation[]>();
|
||||
|
@ -51,6 +56,7 @@ export const GroupComponent = ({ name, label, helpText }: ComponentProps) => {
|
|||
<HelpItem helpText={t(helpText!)} fieldLabelId={`${label}`} />
|
||||
}
|
||||
fieldId={name!}
|
||||
isRequired={required}
|
||||
>
|
||||
<InputGroup>
|
||||
<ChipGroup>
|
||||
|
|
|
@ -18,6 +18,7 @@ export const ListComponent = ({
|
|||
helpText,
|
||||
defaultValue,
|
||||
options,
|
||||
required,
|
||||
isDisabled = false,
|
||||
}: ComponentProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
@ -29,6 +30,7 @@ export const ListComponent = ({
|
|||
label={t(label!)}
|
||||
labelIcon={<HelpItem helpText={t(helpText!)} fieldLabelId={`${label}`} />}
|
||||
fieldId={name!}
|
||||
isRequired={required}
|
||||
>
|
||||
<Controller
|
||||
name={convertToName(name!)}
|
||||
|
|
|
@ -22,7 +22,12 @@ type IdKeyValueType = KeyValueType & {
|
|||
id: number;
|
||||
};
|
||||
|
||||
export const MapComponent = ({ name, label, helpText }: ComponentProps) => {
|
||||
export const MapComponent = ({
|
||||
name,
|
||||
label,
|
||||
helpText,
|
||||
required,
|
||||
}: ComponentProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { getValues, setValue, register } = useFormContext();
|
||||
|
@ -65,6 +70,7 @@ export const MapComponent = ({ name, label, helpText }: ComponentProps) => {
|
|||
label={t(label!)}
|
||||
labelIcon={<HelpItem helpText={t(helpText!)} fieldLabelId={`${label}`} />}
|
||||
fieldId={name!}
|
||||
isRequired={required}
|
||||
>
|
||||
<Flex direction={{ default: "column" }}>
|
||||
<Flex>
|
||||
|
|
|
@ -28,6 +28,7 @@ export const MultiValuedListComponent = ({
|
|||
options,
|
||||
isDisabled = false,
|
||||
stringify,
|
||||
required,
|
||||
}: ComponentProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { control } = useFormContext();
|
||||
|
@ -38,6 +39,7 @@ export const MultiValuedListComponent = ({
|
|||
label={t(label!)}
|
||||
labelIcon={<HelpItem helpText={t(helpText!)} fieldLabelId={`${label}`} />}
|
||||
fieldId={name!}
|
||||
isRequired={required}
|
||||
>
|
||||
<Controller
|
||||
name={convertToName(name!)}
|
||||
|
|
|
@ -12,6 +12,7 @@ export const MultiValuedStringComponent = ({
|
|||
defaultValue,
|
||||
helpText,
|
||||
stringify,
|
||||
required,
|
||||
isDisabled = false,
|
||||
}: ComponentProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
@ -22,6 +23,7 @@ export const MultiValuedStringComponent = ({
|
|||
label={t(label!)}
|
||||
labelIcon={<HelpItem helpText={t(helpText!)} fieldLabelId={`${label}`} />}
|
||||
fieldId={name!}
|
||||
isRequired={required}
|
||||
>
|
||||
<MultiLineInput
|
||||
aria-label={t(label!)}
|
||||
|
|
|
@ -12,6 +12,7 @@ export const PasswordComponent = ({
|
|||
label,
|
||||
helpText,
|
||||
defaultValue,
|
||||
required,
|
||||
isDisabled = false,
|
||||
}: ComponentProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
@ -22,6 +23,7 @@ export const PasswordComponent = ({
|
|||
label={t(label!)}
|
||||
labelIcon={<HelpItem helpText={t(helpText!)} fieldLabelId={`${label}`} />}
|
||||
fieldId={name!}
|
||||
isRequired={required}
|
||||
>
|
||||
<PasswordInput
|
||||
id={name!}
|
||||
|
|
|
@ -28,6 +28,7 @@ export const RoleComponent = ({
|
|||
label,
|
||||
helpText,
|
||||
defaultValue,
|
||||
required,
|
||||
isDisabled = false,
|
||||
}: ComponentProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
@ -47,6 +48,7 @@ export const RoleComponent = ({
|
|||
validated={errors[fieldName] ? "error" : "default"}
|
||||
helperTextInvalid={t("required")}
|
||||
fieldId={name!}
|
||||
isRequired={required}
|
||||
>
|
||||
<Controller
|
||||
name={fieldName}
|
||||
|
|
|
@ -12,6 +12,7 @@ export const ScriptComponent = ({
|
|||
label,
|
||||
helpText,
|
||||
defaultValue,
|
||||
required,
|
||||
isDisabled = false,
|
||||
}: ComponentProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
@ -27,6 +28,7 @@ export const ScriptComponent = ({
|
|||
/>
|
||||
}
|
||||
fieldId={name!}
|
||||
isRequired={required}
|
||||
>
|
||||
<Controller
|
||||
name={convertToName(name!)}
|
||||
|
|
|
@ -13,6 +13,7 @@ export const StringComponent = ({
|
|||
helpText,
|
||||
defaultValue,
|
||||
isDisabled = false,
|
||||
required,
|
||||
}: ComponentProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { register } = useFormContext();
|
||||
|
@ -22,6 +23,7 @@ export const StringComponent = ({
|
|||
label={t(label!)}
|
||||
labelIcon={<HelpItem helpText={t(helpText!)} fieldLabelId={`${label}`} />}
|
||||
fieldId={name!}
|
||||
isRequired={required}
|
||||
>
|
||||
<KeycloakTextInput
|
||||
id={name!}
|
||||
|
|
|
@ -12,6 +12,7 @@ export const TextComponent = ({
|
|||
label,
|
||||
helpText,
|
||||
defaultValue,
|
||||
required,
|
||||
isDisabled = false,
|
||||
}: ComponentProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
@ -22,6 +23,7 @@ export const TextComponent = ({
|
|||
label={t(label!)}
|
||||
labelIcon={<HelpItem helpText={t(helpText!)} fieldLabelId={`${label}`} />}
|
||||
fieldId={name!}
|
||||
required={required}
|
||||
>
|
||||
<KeycloakTextArea
|
||||
id={name!}
|
||||
|
|
|
@ -16,4 +16,5 @@ export interface ConfigPropertyRepresentation {
|
|||
defaultValue?: any;
|
||||
options?: string[];
|
||||
secret?: boolean;
|
||||
required?: boolean;
|
||||
}
|
||||
|
|
|
@ -9,4 +9,5 @@ export interface ConfigPropertyRepresentation {
|
|||
defaultValue?: object;
|
||||
options?: string[];
|
||||
secret?: boolean;
|
||||
required?: boolean;
|
||||
}
|
||||
|
|
|
@ -951,6 +951,7 @@ public class ModelToRepresentation {
|
|||
propRep.setOptions(prop.getOptions());
|
||||
propRep.setHelpText(prop.getHelpText());
|
||||
propRep.setSecret(prop.isSecret());
|
||||
propRep.setRequired(prop.isRequired());
|
||||
return propRep;
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ public class ProviderConfigProperty {
|
|||
protected Object defaultValue;
|
||||
protected List<String> options;
|
||||
protected boolean secret;
|
||||
protected boolean required;
|
||||
private boolean readOnly;
|
||||
|
||||
public ProviderConfigProperty() {
|
||||
|
@ -97,6 +98,11 @@ public class ProviderConfigProperty {
|
|||
this.secret = secret;
|
||||
}
|
||||
|
||||
public ProviderConfigProperty(String name, String label, String helpText, String type, Object defaultValue, boolean secret, boolean required) {
|
||||
this(name, label, helpText, type, defaultValue, secret);
|
||||
this.required = required;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the config variable stored in the database
|
||||
*
|
||||
|
@ -190,6 +196,17 @@ public class ProviderConfigProperty {
|
|||
this.secret = secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, the configuration property must be specified
|
||||
*/
|
||||
public boolean isRequired() {
|
||||
return required;
|
||||
}
|
||||
|
||||
public void setRequired(boolean required) {
|
||||
this.required = required;
|
||||
}
|
||||
|
||||
public void setReadOnly(boolean readOnly) {
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ public class ProviderConfigurationBuilder {
|
|||
private Object defaultValue;
|
||||
private List<String> options;
|
||||
private boolean secret;
|
||||
private boolean required;
|
||||
|
||||
public ProviderConfigPropertyBuilder name(String name) {
|
||||
this.name = name;
|
||||
|
@ -168,6 +169,17 @@ public class ProviderConfigurationBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If turned on, this property will be marked as required in the admin console
|
||||
*
|
||||
* @param required
|
||||
* @return
|
||||
*/
|
||||
public ProviderConfigPropertyBuilder required(boolean required) {
|
||||
this.required = required;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the current property, and start building the next one
|
||||
*
|
||||
|
@ -182,6 +194,7 @@ public class ProviderConfigurationBuilder {
|
|||
property.setDefaultValue(defaultValue);
|
||||
property.setOptions(options);
|
||||
property.setSecret(secret);
|
||||
property.setRequired(required);
|
||||
ProviderConfigurationBuilder.this.properties.add(property);
|
||||
return ProviderConfigurationBuilder.this;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue