Skip to content

Commit c21ea31

Browse files
committed
Support authenticated request through the API
Allow to specify the context/user names when sending a request or accessing a URL through the API. Signed-off-by: thc202 <thc202@gmail.com>
1 parent e1f9454 commit c21ea31

2 files changed

Lines changed: 70 additions & 7 deletions

File tree

zap/src/main/java/org/zaproxy/zap/extension/api/CoreAPI.java

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import net.sf.json.JSONObject;
5050
import org.apache.commons.httpclient.URI;
5151
import org.apache.commons.httpclient.URIException;
52+
import org.apache.commons.lang3.StringUtils;
5253
import org.apache.commons.lang3.Strings;
5354
import org.apache.logging.log4j.Level;
5455
import org.apache.logging.log4j.LogManager;
@@ -78,12 +79,16 @@
7879
import org.zaproxy.zap.extension.alert.AlertAPI;
7980
import org.zaproxy.zap.extension.alert.AlertParam;
8081
import org.zaproxy.zap.extension.alert.ExtensionAlert;
82+
import org.zaproxy.zap.extension.api.ApiException.Type;
83+
import org.zaproxy.zap.extension.users.ExtensionUserManagement;
84+
import org.zaproxy.zap.model.Context;
8185
import org.zaproxy.zap.model.SessionStructure;
8286
import org.zaproxy.zap.model.SessionUtils;
8387
import org.zaproxy.zap.model.StructuralNode;
8488
import org.zaproxy.zap.network.DomainMatcher;
8589
import org.zaproxy.zap.network.HttpRedirectionValidator;
8690
import org.zaproxy.zap.network.HttpRequestConfig;
91+
import org.zaproxy.zap.users.User;
8792
import org.zaproxy.zap.utils.ApiUtils;
8893
import org.zaproxy.zap.utils.ZapSupportUtils;
8994

@@ -187,6 +192,7 @@ private enum ScanReportType {
187192
private static final String OTHER_FILE_UPLOAD = "fileUpload";
188193

189194
private static final String PARAM_BASE_URL = "baseurl";
195+
private static final String PARAM_CONTEXT_NAME = "contextName";
190196
private static final String PARAM_COUNT = "count";
191197
private static final String PARAM_DIR = "dir";
192198
private static final String PARAM_SESSION = "name";
@@ -216,6 +222,7 @@ private enum ScanReportType {
216222
private static final String PARAM_CONTENTS = "fileContents";
217223
private static final String PARAM_NAME = "name";
218224
private static final String PARAM_LEVEL = "logLevel";
225+
private static final String PARAM_USER_NAME = "userName";
219226

220227
private static final List<String> PARAMS_STRING = Collections.singletonList("String");
221228
private static final List<String> PARAMS_BOOLEAN = Collections.singletonList("Boolean");
@@ -269,7 +276,9 @@ public CoreAPI() {
269276
new ApiAction(
270277
ACTION_ACCESS_URL,
271278
new String[] {PARAM_URL},
272-
new String[] {PARAM_FOLLOW_REDIRECTS}));
279+
new String[] {
280+
PARAM_FOLLOW_REDIRECTS, PARAM_CONTEXT_NAME, PARAM_USER_NAME
281+
}));
273282
this.addApiAction(new ApiAction(ACTION_SHUTDOWN));
274283
this.addApiAction(
275284
new ApiAction(
@@ -296,7 +305,9 @@ public CoreAPI() {
296305
new ApiAction(
297306
ACTION_SEND_REQUEST,
298307
new String[] {PARAM_REQUEST},
299-
new String[] {PARAM_FOLLOW_REDIRECTS}));
308+
new String[] {
309+
PARAM_FOLLOW_REDIRECTS, PARAM_CONTEXT_NAME, PARAM_USER_NAME
310+
}));
300311
this.addApiAction(new ApiAction(ACTION_COLLECT_GARBAGE));
301312
this.addApiAction(
302313
new ApiAction(
@@ -431,7 +442,9 @@ public CoreAPI() {
431442
new ApiOther(
432443
OTHER_SEND_HAR_REQUEST,
433444
new String[] {PARAM_REQUEST},
434-
new String[] {PARAM_FOLLOW_REDIRECTS})));
445+
new String[] {
446+
PARAM_FOLLOW_REDIRECTS, PARAM_CONTEXT_NAME, PARAM_USER_NAME
447+
})));
435448
this.addApiOthers(new ApiOther(OTHER_FILE_DOWNLOAD, new String[] {PARAM_FILENAME}));
436449
this.addApiOthers(
437450
new ApiOther(
@@ -545,7 +558,11 @@ public ApiResponse handleApiAction(String name, JSONObject params) throws ApiExc
545558
} catch (HttpMalformedHeaderException e) {
546559
throw new ApiException(ApiException.Type.ILLEGAL_PARAMETER, PARAM_URL, e);
547560
}
548-
return sendHttpMessage(request, getParam(params, PARAM_FOLLOW_REDIRECTS, false), name);
561+
return sendHttpMessage(
562+
request,
563+
getParam(params, PARAM_FOLLOW_REDIRECTS, false),
564+
getUser(params),
565+
name);
549566
} else if (ACTION_SHUTDOWN.equals(name)) {
550567
Thread thread =
551568
new Thread("ZAP-Shutdown") {
@@ -771,7 +788,11 @@ public void run() {
771788
throw new ApiException(ApiException.Type.ILLEGAL_PARAMETER, PARAM_REQUEST, e);
772789
}
773790
validateForCurrentMode(request);
774-
return sendHttpMessage(request, getParam(params, PARAM_FOLLOW_REDIRECTS, false), name);
791+
return sendHttpMessage(
792+
request,
793+
getParam(params, PARAM_FOLLOW_REDIRECTS, false),
794+
getUser(params),
795+
name);
775796
} else if (ACTION_DELETE_ALL_ALERTS.equals(name)) {
776797
return API.getInstance()
777798
.getImplementors()
@@ -931,6 +952,36 @@ public void run() {
931952
return ApiResponseElement.OK;
932953
}
933954

955+
private static User getUser(JSONObject params) throws ApiException {
956+
String userName = params.optString(PARAM_USER_NAME, "");
957+
if (StringUtils.isBlank(userName)) {
958+
return null;
959+
}
960+
961+
ExtensionUserManagement usersExtension =
962+
Control.getSingleton()
963+
.getExtensionLoader()
964+
.getExtension(ExtensionUserManagement.class);
965+
if (usersExtension == null) {
966+
throw new ApiException(Type.NO_IMPLEMENTOR, ExtensionUserManagement.NAME);
967+
}
968+
969+
String contextName = params.optString(PARAM_CONTEXT_NAME, "");
970+
if (StringUtils.isBlank(contextName)) {
971+
throw new ApiException(Type.MISSING_PARAMETER, PARAM_CONTEXT_NAME);
972+
}
973+
974+
Context context = ApiUtils.getContextByName(contextName);
975+
List<User> users = usersExtension.getContextUserAuthManager(context.getId()).getUsers();
976+
for (User user : users) {
977+
if (userName.equals(user.getName())) {
978+
return user;
979+
}
980+
}
981+
982+
throw new ApiException(Type.USER_NOT_FOUND, PARAM_USER_NAME);
983+
}
984+
934985
/**
935986
* Returns a Path for the child file underneath the specified parent directory. Detects and
936987
* throws an exception if a path traversal attack is used.
@@ -1029,13 +1080,14 @@ private static boolean isValidForCurrentMode(URI uri) {
10291080
}
10301081

10311082
private ApiResponse sendHttpMessage(
1032-
HttpMessage request, boolean followRedirects, String apiResponseName)
1083+
HttpMessage request, boolean followRedirects, User user, String apiResponseName)
10331084
throws ApiException {
10341085
final ApiResponseList resultList = new ApiResponseList(apiResponseName);
10351086
try {
10361087
sendRequest(
10371088
request,
10381089
followRedirects,
1090+
user,
10391091
new Processor<HttpMessage>() {
10401092

10411093
@Override
@@ -1086,9 +1138,13 @@ private static HttpMessage createRequest(String request) throws HttpMalformedHea
10861138
}
10871139

10881140
private static void sendRequest(
1089-
HttpMessage request, boolean followRedirects, Processor<HttpMessage> processor)
1141+
HttpMessage request,
1142+
boolean followRedirects,
1143+
User user,
1144+
Processor<HttpMessage> processor)
10901145
throws IOException, ApiException {
10911146
HttpSender sender = new HttpSender(HttpSender.MANUAL_REQUEST_INITIATOR);
1147+
sender.setUser(user);
10921148

10931149
if (followRedirects) {
10941150
ModeRedirectionValidator redirector = new ModeRedirectionValidator(processor);
@@ -1508,6 +1564,7 @@ private HttpMessage handleApiOtherImpl(HttpMessage msg, String name, JSONObject
15081564
sendRequest(
15091565
request,
15101566
followRedirects,
1567+
getUser(params),
15111568
httpMessage -> {
15121569
HistoryReference hRef = httpMessage.getHistoryRef();
15131570
entries.addEntry(

zap/src/main/resources/org/zaproxy/zap/resources/Messages.properties

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,8 +1314,10 @@ copy.copy.popup = Copy
13141314
copy.desc = Provides a right click option to copy highlighted text
13151315

13161316
core.api.action.accessUrl = Convenient and simple action to access a URL, optionally following redirections. Returns the request sent and response received and followed redirections, if any. Other actions are available which offer more control on what is sent, like, 'sendRequest' or 'sendHarRequest'.
1317+
core.api.action.accessUrl.param.contextName = The user's context, ignored if the user name is not provided.
13171318
core.api.action.accessUrl.param.followRedirects =
13181319
core.api.action.accessUrl.param.url =
1320+
core.api.action.accessUrl.param.userName = The name of the user to access the URL with.
13191321
core.api.action.addProxyChainExcludedDomain = Adds a domain to be excluded from the outgoing proxy, using the specified value. Optionally sets if the new entry is enabled (default, true) and whether or not the new value is specified as a regex (default, false).
13201322
core.api.action.addProxyChainExcludedDomain.param.isEnabled =
13211323
core.api.action.addProxyChainExcludedDomain.param.isRegex =
@@ -1357,8 +1359,10 @@ core.api.action.saveSession = Saves the session.
13571359
core.api.action.saveSession.param.name = The name (or path) of the session. If a relative path is specified it will be resolved against the "session" directory in ZAP "home" dir.
13581360
core.api.action.saveSession.param.overwrite = If existing files should be overwritten, attempting to overwrite the files of the session already in use/saved will lead to an error ("already_exists").
13591361
core.api.action.sendRequest = Sends the HTTP request, optionally following redirections. Returns the request sent and response received and followed redirections, if any. The Mode is enforced when sending the request (and following redirections), custom manual requests are not allowed in 'Safe' mode nor in 'Protected' mode if out of scope.
1362+
core.api.action.sendRequest.param.contextName = The user's context, ignored if the user name is not provided.
13601363
core.api.action.sendRequest.param.followRedirects =
13611364
core.api.action.sendRequest.param.request =
1365+
core.api.action.sendRequest.param.userName = The name of the user to send the request with.
13621366
core.api.action.setHomeDirectory =
13631367
core.api.action.setHomeDirectory.param.dir =
13641368
core.api.action.setLogLevel = Sets the logging level for a given logger name.
@@ -1430,8 +1434,10 @@ core.api.other.messagesHarById.param.ids =
14301434
core.api.other.proxy.pac =
14311435
core.api.other.rootcert = Gets the Root CA certificate used by the local proxies.
14321436
core.api.other.sendHarRequest = Sends the first HAR request entry, optionally following redirections. Returns, in HAR format, the request sent and response received and followed redirections, if any. The Mode is enforced when sending the request (and following redirections), custom manual requests are not allowed in 'Safe' mode nor in 'Protected' mode if out of scope.
1437+
core.api.other.sendHarRequest.param.contextName = The user's context, ignored if the user name is not provided.
14331438
core.api.other.sendHarRequest.param.followRedirects =
14341439
core.api.other.sendHarRequest.param.request =
1440+
core.api.other.sendHarRequest.param.userName = The name of the user to send the request with.
14351441
core.api.other.setproxy =
14361442
core.api.other.setproxy.param.proxy =
14371443
core.api.other.xmlreport = Generates a report in XML format

0 commit comments

Comments
 (0)