3636import java .io .StringWriter ;
3737import java .lang .invoke .MethodHandles ;
3838import java .lang .reflect .Array ;
39+ import java .lang .reflect .Field ;
3940import java .lang .reflect .InvocationTargetException ;
4041import java .lang .reflect .Method ;
42+ import java .lang .reflect .ParameterizedType ;
43+ import java .lang .reflect .Type ;
4144import java .net .URI ;
4245import java .net .URL ;
4346import java .nio .charset .StandardCharsets ;
132135import org .apache .activemq .artemis .core .server .plugin .ActiveMQServerResourcePlugin ;
133136import org .apache .activemq .artemis .core .server .plugin .ActiveMQServerSessionPlugin ;
134137import org .apache .activemq .artemis .core .settings .impl .AddressSettings ;
138+ import org .apache .activemq .artemis .core .settings .impl .AuthenticationCacheKeyConfig ;
135139import org .apache .activemq .artemis .core .settings .impl .ResourceLimitSettings ;
136140import org .apache .activemq .artemis .json .JsonArrayBuilder ;
137141import org .apache .activemq .artemis .json .JsonObject ;
@@ -172,6 +176,8 @@ public class ConfigurationImpl extends javax.security.auth.login.Configuration i
172176
173177 public static final JournalType DEFAULT_JOURNAL_TYPE = JournalType .ASYNCIO ;
174178
179+ public static final EnumSet <AuthenticationCacheKeyConfig > DEFAULT_AUTHENTICATION_CACHE_KEY = EnumSet .of (AuthenticationCacheKeyConfig .USER , AuthenticationCacheKeyConfig .PASS , AuthenticationCacheKeyConfig .TLS_SUBJECT_DN );
180+
175181 public static final String PROPERTY_CLASS_SUFFIX = ".class" ;
176182
177183 public static final String REDACTED = "**redacted**" ;
@@ -491,6 +497,8 @@ public class ConfigurationImpl extends javax.security.auth.login.Configuration i
491497
492498 private Map <String , JaasAppConfiguration > jaasConfigs = new ConcurrentHashMap <>();
493499
500+ private EnumSet <AuthenticationCacheKeyConfig > authenticationCacheKey = EnumSet .copyOf (DEFAULT_AUTHENTICATION_CACHE_KEY );
501+
494502 /**
495503 * Parent folder for all data folders.
496504 */
@@ -646,7 +654,7 @@ public void parsePrefixedProperties(Properties properties, String prefix) throws
646654
647655 @ Override
648656 public void parsePrefixedProperties (Object target , String name , Properties properties , String prefix ) throws Exception {
649- Map <String , Object > beanProperties = new LinkedHashMap <>();
657+ Map <String , String > beanProperties = new LinkedHashMap <>();
650658 final Checksum checksum = new Adler32 ();
651659 synchronized (properties ) {
652660 String key = null ;
@@ -706,7 +714,7 @@ public AppConfigurationEntry[] getAppConfigurationEntry(String realm) {
706714 }
707715 }
708716
709- public void populateWithProperties (final Object target , final String propsId , Map <String , Object > beanProperties ) throws InvocationTargetException , IllegalAccessException {
717+ public void populateWithProperties (final Object target , final String propsId , Map <String , String > beanProperties ) throws InvocationTargetException , IllegalAccessException {
710718 CollectionAutoFillPropertiesUtil autoFillCollections = new CollectionAutoFillPropertiesUtil (getBrokerPropertiesRemoveValue (beanProperties ));
711719 BeanUtilsBean beanUtils = new BeanUtilsBean (new ConvertUtilsBean (), autoFillCollections ) {
712720
@@ -1004,15 +1012,17 @@ public <T> T convert(Class<T> type, Object value) {
10041012
10051013 Map <String , String > errors = new LinkedHashMap <>();
10061014 // Loop through the property name/value pairs to be set
1007- for (final Map .Entry <String , ? extends Object > entry : beanProperties .entrySet ()) {
1015+ for (final Map .Entry <String , String > entry : beanProperties .entrySet ()) {
10081016 // Identify the property name and value(s) to be assigned
10091017 final String name = entry .getKey ();
10101018 try {
10111019 if (logger .isDebugEnabled ()) {
10121020 logger .debug ("set property target={}, name = {}, value = {}" , target .getClass (), name , entry .getValue ());
10131021 }
1014- // Perform the assignment for this property
1015- beanUtils .setProperty (target , name , entry .getValue ());
1022+ // Perform the assignment for this property with special handling for EnumSet
1023+ if (!handleEnumSet (target , name , entry .getValue ())) {
1024+ beanUtils .setProperty (target , name , entry .getValue ());
1025+ }
10161026 } catch (InvocationTargetException invocationTargetException ) {
10171027 logger .trace ("failed to populate property with key: {}" , name , invocationTargetException );
10181028 Throwable toLog = invocationTargetException ;
@@ -1028,6 +1038,59 @@ public <T> T convert(Class<T> type, Object value) {
10281038 updateApplyStatus (propsId , errors );
10291039 }
10301040
1041+ /*
1042+ * Since an EnumSet relies on parameterized typing BeanUtils can't handle them directly. Therefore, we need to handle
1043+ * them manually.
1044+ */
1045+ private boolean handleEnumSet (Object target , String name , String value ) throws IllegalAccessException {
1046+ boolean result = false ;
1047+ Field field = getField (target .getClass (), name );
1048+ if (field != null && EnumSet .class .isAssignableFrom (field .getType ())) {
1049+ // Extract the <E> from EnumSet<E>
1050+ Class <? extends Enum > enumClass = getEnumClassFromField (field );
1051+ if (enumClass != null ) {
1052+ EnumSet <?> enumSet = convertToEnumSet (enumClass , value );
1053+ field .setAccessible (true );
1054+ field .set (target , enumSet );
1055+ result = true ;
1056+ }
1057+ }
1058+ return result ;
1059+ }
1060+
1061+ private static Class <? extends Enum > getEnumClassFromField (Field field ) {
1062+ if (field .getGenericType () instanceof ParameterizedType parameterizedType ) {
1063+ Type [] actualTypeArguments = parameterizedType .getActualTypeArguments ();
1064+ if (actualTypeArguments .length > 0 && actualTypeArguments [0 ] instanceof Class ) {
1065+ return (Class <? extends Enum >) actualTypeArguments [0 ];
1066+ }
1067+ }
1068+ return null ;
1069+ }
1070+
1071+ private static <E extends Enum <E >> EnumSet <E > convertToEnumSet (Class <E > enumClass , String csv ) {
1072+ if (csv == null || csv .trim ().isEmpty ()) {
1073+ return EnumSet .noneOf (enumClass );
1074+ }
1075+
1076+ return Arrays .stream (csv .split ("," ))
1077+ .map (String ::trim )
1078+ .filter (s -> !s .isEmpty ())
1079+ .map (s -> Enum .valueOf (enumClass , s ))
1080+ .collect (Collectors .toCollection (() -> EnumSet .noneOf (enumClass )));
1081+ }
1082+
1083+ private static Field getField (Class <?> clazz , String fieldName ) {
1084+ while (clazz != null ) {
1085+ try {
1086+ return clazz .getDeclaredField (fieldName );
1087+ } catch (NoSuchFieldException e ) {
1088+ clazz = clazz .getSuperclass ();
1089+ }
1090+ }
1091+ return null ;
1092+ }
1093+
10311094 @ Override
10321095 public void exportAsProperties (File file ) throws Exception {
10331096 try (FileWriter writer = new FileWriter (file , StandardCharsets .UTF_8 )) {
@@ -1299,17 +1362,17 @@ private synchronized void updateReadPropertiesStatus(String propsId, long alder3
12991362 this .jsonStatus = JsonUtil .mergeAndUpdate (jsonStatus , jsonObjectBuilder .build ());
13001363 }
13011364
1302- private String getBrokerPropertiesKeySurround (Map <String , Object > propertiesToApply ) {
1365+ private String getBrokerPropertiesKeySurround (Map <String , String > propertiesToApply ) {
13031366 if (propertiesToApply .containsKey (ActiveMQDefaultConfiguration .BROKER_PROPERTIES_KEY_SURROUND_PROPERTY )) {
1304- return String . valueOf ( propertiesToApply .remove (ActiveMQDefaultConfiguration .BROKER_PROPERTIES_KEY_SURROUND_PROPERTY ) );
1367+ return propertiesToApply .remove (ActiveMQDefaultConfiguration .BROKER_PROPERTIES_KEY_SURROUND_PROPERTY );
13051368 } else {
13061369 return System .getProperty (getSystemPropertyPrefix () + ActiveMQDefaultConfiguration .BROKER_PROPERTIES_KEY_SURROUND_PROPERTY , getBrokerPropertiesKeySurround ());
13071370 }
13081371 }
13091372
1310- private String getBrokerPropertiesRemoveValue (Map <String , Object > propertiesToApply ) {
1373+ private String getBrokerPropertiesRemoveValue (Map <String , String > propertiesToApply ) {
13111374 if (propertiesToApply .containsKey (ActiveMQDefaultConfiguration .BROKER_PROPERTIES_REMOVE_VALUE_PROPERTY )) {
1312- return String . valueOf ( propertiesToApply .remove (ActiveMQDefaultConfiguration .BROKER_PROPERTIES_REMOVE_VALUE_PROPERTY ) );
1375+ return propertiesToApply .remove (ActiveMQDefaultConfiguration .BROKER_PROPERTIES_REMOVE_VALUE_PROPERTY );
13131376 } else {
13141377 return System .getProperty (getSystemPropertyPrefix () + ActiveMQDefaultConfiguration .BROKER_PROPERTIES_REMOVE_VALUE_PROPERTY , getBrokerPropertiesRemoveValue ());
13151378 }
@@ -3576,6 +3639,17 @@ public Configuration addFederationDownstreamAuthorization(String role) {
35763639 return this ;
35773640 }
35783641
3642+ @ Override
3643+ public Configuration setAuthenticationCacheKey (EnumSet <AuthenticationCacheKeyConfig > authenticationCacheKey ) {
3644+ this .authenticationCacheKey = authenticationCacheKey ;
3645+ return this ;
3646+ }
3647+
3648+ @ Override
3649+ public EnumSet <AuthenticationCacheKeyConfig > getAuthenticationCacheKey () {
3650+ return authenticationCacheKey ;
3651+ }
3652+
35793653 // extend property utils with ability to auto-fill and locate from collections
35803654 // collection entries are identified by the name() property
35813655 private static class CollectionAutoFillPropertiesUtil extends PropertyUtilsBean {
0 commit comments