Skip to content

Commit 8c1132e

Browse files
authored
Merge pull request #6531 from JohannesLks/Remove-requirement-to-set-a-header-value-for-headerBasedSessionManagement
authhelper: allow empty header list
2 parents 00275ce + ab8977f commit 8c1132e

File tree

4 files changed

+93
-10
lines changed

4 files changed

+93
-10
lines changed

addOns/authhelper/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1414

1515
## Changed
1616
- Send the referer header on verification if set on the original request.
17+
- Removed requirement to set at least one header in the GUI for Header-Based Session Management.
1718

1819
### Fixed
1920
- Do not fail the authentication on diagnostic errors.

addOns/authhelper/src/main/java/org/zaproxy/addon/authhelper/HeaderBasedSessionManagementMethodType.java

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -456,17 +456,20 @@ public void importData(Configuration config, SessionManagementMethod sessionMeth
456456
@Override
457457
public ApiDynamicActionImplementor getSetMethodForContextApiAction() {
458458
return new ApiDynamicActionImplementor(
459-
API_METHOD_NAME, new String[] {PARAM_HEADERS}, null) {
459+
API_METHOD_NAME, new String[0], new String[] {PARAM_HEADERS}) {
460460

461461
@Override
462462
public void handleAction(JSONObject params) throws ApiException {
463463
Context context =
464464
ApiUtils.getContextByParamId(params, SessionManagementAPI.PARAM_CONTEXT_ID);
465465
HeaderBasedSessionManagementMethod smm =
466466
createSessionManagementMethod(context.getId());
467-
// Headers are newline separated key: value pairs
468-
String[] headerArray = params.getString(PARAM_HEADERS).split("\n");
469-
smm.setHeaderConfigs(getHeaderPairs(headerArray));
467+
String headersStr = params.optString(PARAM_HEADERS, "");
468+
if (!headersStr.isBlank()) {
469+
// Headers are newline separated key: value pairs
470+
String[] headerArray = headersStr.split("\n");
471+
smm.setHeaderConfigs(getHeaderPairs(headerArray));
472+
}
470473
context.setSessionManagementMethod(smm);
471474
}
472475
};
@@ -518,11 +521,6 @@ public void validateFields() throws IllegalStateException {
518521
"authhelper.session.method.header.error.value"));
519522
}
520523
}
521-
if (headers.isEmpty()) {
522-
throw new IllegalStateException(
523-
Constant.messages.getString(
524-
"authhelper.session.method.header.error.headers"));
525-
}
526524
}
527525

528526
@Override

addOns/authhelper/src/main/resources/org/zaproxy/addon/authhelper/resources/Messages.properties

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,6 @@ authhelper.session-detect.name = Session Management Response Identified
150150
authhelper.session-detect.soln = This is an informational alert rather than a vulnerability and so there is nothing to fix.
151151

152152
authhelper.session.method.auto.name = Auto-Detect Session Management
153-
authhelper.session.method.header.error.headers = You must specify at least one header
154153
authhelper.session.method.header.error.json.parse = Unable to parse authentication response body from {0} as JSON: {1}
155154
authhelper.session.method.header.error.value = You must specify both a header and value
156155
authhelper.session.method.header.label.footer = Any number of headers are supported - a new row is added when any characters are added to the last field.\nThe following tokens can be used in the values:\n* {%json:path.to.data%}\tJSON authentication response data\n* {%env:env_var%}\tenvironmental variable\n* {%script:glob_var%}\tglobal script variable\n* {%header:env_var%}\tauthentication response header\n* {%url:key%}\t\tauthentication URL param

addOns/authhelper/src/test/java/org/zaproxy/addon/authhelper/HeaderBasedSessionManagementMethodTypeUnitTest.java

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,14 @@
2222
import static org.hamcrest.CoreMatchers.equalTo;
2323
import static org.hamcrest.CoreMatchers.is;
2424
import static org.hamcrest.MatcherAssert.assertThat;
25+
import static org.hamcrest.Matchers.containsString;
2526
import static org.hamcrest.Matchers.hasSize;
27+
import static org.junit.jupiter.api.Assertions.assertThrows;
2628
import static org.mockito.ArgumentMatchers.anyInt;
2729
import static org.mockito.BDDMockito.given;
2830
import static org.mockito.Mockito.doNothing;
2931
import static org.mockito.Mockito.mock;
32+
import static org.mockito.Mockito.verify;
3033
import static org.mockito.Mockito.when;
3134
import static org.mockito.Mockito.withSettings;
3235

@@ -35,6 +38,7 @@
3538
import java.util.HashMap;
3639
import java.util.List;
3740
import java.util.Map;
41+
import net.sf.json.JSONObject;
3842
import org.apache.commons.httpclient.Cookie;
3943
import org.junit.jupiter.api.BeforeEach;
4044
import org.junit.jupiter.api.Test;
@@ -55,6 +59,7 @@
5559
import org.zaproxy.zap.model.Context;
5660
import org.zaproxy.zap.network.HttpRequestBody;
5761
import org.zaproxy.zap.network.HttpResponseBody;
62+
import org.zaproxy.zap.session.SessionManagementMethod;
5863
import org.zaproxy.zap.testutils.TestUtils;
5964
import org.zaproxy.zap.utils.Pair;
6065
import org.zaproxy.zap.utils.ZapXmlConfiguration;
@@ -389,4 +394,84 @@ void shouldParseHeaderValuesProperly(String entry, String expectedFirst, String
389394
assertThat(header.first, is(equalTo(expectedFirst)));
390395
assertThat(header.second, is(equalTo(expectedSecond)));
391396
}
397+
398+
@ParameterizedTest
399+
@CsvSource(value = {"'',0", "Header1:Value1,1", "Header:, 1"})
400+
void shouldSetHeaderConfigsFromApi(String headers, int expectedSize) throws ApiException {
401+
// Given
402+
HeaderBasedSessionManagementMethodType type = new HeaderBasedSessionManagementMethodType();
403+
Context context = mock(Context.class);
404+
JSONObject params = new JSONObject();
405+
params.put("contextId", 1);
406+
params.put("headers", headers);
407+
408+
Model model = mock(Model.class, withSettings().strictness(Strictness.LENIENT));
409+
Model.setSingletonForTesting(model);
410+
Session session = mock(Session.class);
411+
given(model.getSession()).willReturn(session);
412+
given(session.getContext(1)).willReturn(context);
413+
414+
// When
415+
type.getSetMethodForContextApiAction().handleAction(params);
416+
417+
// Then
418+
ArgumentCaptor<SessionManagementMethod> captor =
419+
ArgumentCaptor.forClass(SessionManagementMethod.class);
420+
verify(context).setSessionManagementMethod(captor.capture());
421+
HeaderBasedSessionManagementMethod savedMethod =
422+
(HeaderBasedSessionManagementMethod) captor.getValue();
423+
assertThat(savedMethod.getHeaderConfigs(), hasSize(expectedSize));
424+
}
425+
426+
@ParameterizedTest
427+
@CsvSource(value = {"' \\t\\n '", "Header"})
428+
void shouldRejectInvalidHeaderConfigsFromApi(String headers) {
429+
// Given
430+
HeaderBasedSessionManagementMethodType type = new HeaderBasedSessionManagementMethodType();
431+
Context context = mock(Context.class);
432+
JSONObject params = new JSONObject();
433+
params.put("contextId", 1);
434+
params.put("headers", headers);
435+
436+
Model model = mock(Model.class, withSettings().strictness(Strictness.LENIENT));
437+
Model.setSingletonForTesting(model);
438+
Session session = mock(Session.class);
439+
given(model.getSession()).willReturn(session);
440+
given(session.getContext(1)).willReturn(context);
441+
442+
// When / Then
443+
ApiException e =
444+
assertThrows(
445+
ApiException.class,
446+
() -> type.getSetMethodForContextApiAction().handleAction(params));
447+
448+
assertThat(e.getType(), is(equalTo(ApiException.Type.ILLEGAL_PARAMETER)));
449+
assertThat(e.getMessage(), is(containsString("headers")));
450+
}
451+
452+
@Test
453+
void shouldSetHeaderConfigsFromApiWhenParamMissing() throws ApiException {
454+
// Given
455+
HeaderBasedSessionManagementMethodType type = new HeaderBasedSessionManagementMethodType();
456+
Context context = mock(Context.class);
457+
JSONObject params = new JSONObject();
458+
params.put("contextId", 1);
459+
460+
Model model = mock(Model.class, withSettings().strictness(Strictness.LENIENT));
461+
Model.setSingletonForTesting(model);
462+
Session session = mock(Session.class);
463+
given(model.getSession()).willReturn(session);
464+
given(session.getContext(1)).willReturn(context);
465+
466+
// When
467+
type.getSetMethodForContextApiAction().handleAction(params);
468+
469+
// Then
470+
ArgumentCaptor<SessionManagementMethod> captor =
471+
ArgumentCaptor.forClass(SessionManagementMethod.class);
472+
verify(context).setSessionManagementMethod(captor.capture());
473+
HeaderBasedSessionManagementMethod savedMethod =
474+
(HeaderBasedSessionManagementMethod) captor.getValue();
475+
assertThat(savedMethod.getHeaderConfigs(), hasSize(0));
476+
}
392477
}

0 commit comments

Comments
 (0)