diff --git a/addOns/authhelper/CHANGELOG.md b/addOns/authhelper/CHANGELOG.md index fd003091e0..8beccb96ed 100644 --- a/addOns/authhelper/CHANGELOG.md +++ b/addOns/authhelper/CHANGELOG.md @@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Fixed - Bug where some of the data structures were not being reset when the session changed. +- Address concurrent modification exceptions. ## [0.23.0] - 2025-03-04 ### Added diff --git a/addOns/authhelper/src/main/java/org/zaproxy/addon/authhelper/AuthUtils.java b/addOns/authhelper/src/main/java/org/zaproxy/addon/authhelper/AuthUtils.java index 216d516334..23a2ee79ec 100644 --- a/addOns/authhelper/src/main/java/org/zaproxy/addon/authhelper/AuthUtils.java +++ b/addOns/authhelper/src/main/java/org/zaproxy/addon/authhelper/AuthUtils.java @@ -160,7 +160,8 @@ public class AuthUtils { * the last known good value, in the case where we don't see the token set in the authentication * response. */ - private static Map> requestTokenMap = new HashMap<>(); + private static Map> requestTokenMap = + Collections.synchronizedMap(new HashMap<>()); /** * The best verification request we have found for a context. There will only be a verification @@ -168,7 +169,8 @@ public class AuthUtils { * session management to auto-detect, setting the checking strategy to "poll" but not specified * a URL. */ - private static Map contextVerifMap = new HashMap<>(); + private static Map contextVerifMap = + Collections.synchronizedMap(new HashMap<>()); /** * The best session management request we have found for a context. There will only be a @@ -176,13 +178,14 @@ public class AuthUtils { * by setting session management to auto-detect. */ private static Map contextSessionMgmtMap = - new HashMap<>(); + Collections.synchronizedMap(new HashMap<>()); /** * The URLs (and methods) we've checked for finding good verification requests. These will only * be recorded if the user has set verification to auto-detect. */ - private static Map> contextVerificationMap = new HashMap<>(); + private static Map> contextVerificationMap = + Collections.synchronizedMap(new HashMap<>()); public static long getTimeToWaitMs() { return timeToWaitMs; @@ -1056,7 +1059,7 @@ public static void processVerificationDetails( + details.getMsg().getRequestHeader().getURI().toString(); if (contextVerificationMap - .computeIfAbsent(context.getId(), c -> new HashSet<>()) + .computeIfAbsent(context.getId(), c -> Collections.synchronizedSet(new HashSet<>())) .add(methodUrl)) { // Have not already checked this method + url getExecutorService().submit(new VerificationDetectionProcessor(context, details, rule)); @@ -1067,10 +1070,14 @@ public static void recordRequestSessionToken(Context context, String key, String recordRequestSessionToken(context.getId(), key, value); } + private static Map computeIfAbsent( + Map> inputMap, int contextId) { + return inputMap.computeIfAbsent( + contextId, c -> Collections.synchronizedMap(new HashMap<>())); + } + public static void recordRequestSessionToken(int contextId, String key, String value) { - requestTokenMap - .computeIfAbsent(contextId, c -> new HashMap<>()) - .put(key.toLowerCase(Locale.ROOT), value); + computeIfAbsent(requestTokenMap, contextId).put(key.toLowerCase(Locale.ROOT), value); } public static String getRequestSessionToken(Context context, String key) { @@ -1078,9 +1085,7 @@ public static String getRequestSessionToken(Context context, String key) { } public static String getRequestSessionToken(int contextId, String key) { - return requestTokenMap - .computeIfAbsent(contextId, c -> new HashMap<>()) - .get(key.toLowerCase(Locale.ROOT)); + return computeIfAbsent(requestTokenMap, contextId).get(key.toLowerCase(Locale.ROOT)); } static class AuthenticationBrowserHook implements BrowserHook {