Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 64 additions & 7 deletions zap/src/main/java/org/zaproxy/zap/extension/api/CoreAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import net.sf.json.JSONObject;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.URIException;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Strings;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
Expand Down Expand Up @@ -78,12 +79,16 @@
import org.zaproxy.zap.extension.alert.AlertAPI;
import org.zaproxy.zap.extension.alert.AlertParam;
import org.zaproxy.zap.extension.alert.ExtensionAlert;
import org.zaproxy.zap.extension.api.ApiException.Type;
import org.zaproxy.zap.extension.users.ExtensionUserManagement;
import org.zaproxy.zap.model.Context;
import org.zaproxy.zap.model.SessionStructure;
import org.zaproxy.zap.model.SessionUtils;
import org.zaproxy.zap.model.StructuralNode;
import org.zaproxy.zap.network.DomainMatcher;
import org.zaproxy.zap.network.HttpRedirectionValidator;
import org.zaproxy.zap.network.HttpRequestConfig;
import org.zaproxy.zap.users.User;
import org.zaproxy.zap.utils.ApiUtils;
import org.zaproxy.zap.utils.ZapSupportUtils;

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

private static final String PARAM_BASE_URL = "baseurl";
private static final String PARAM_CONTEXT_NAME = "contextName";
private static final String PARAM_COUNT = "count";
private static final String PARAM_DIR = "dir";
private static final String PARAM_SESSION = "name";
Expand Down Expand Up @@ -216,6 +222,7 @@ private enum ScanReportType {
private static final String PARAM_CONTENTS = "fileContents";
private static final String PARAM_NAME = "name";
private static final String PARAM_LEVEL = "logLevel";
private static final String PARAM_USER_NAME = "userName";

private static final List<String> PARAMS_STRING = Collections.singletonList("String");
private static final List<String> PARAMS_BOOLEAN = Collections.singletonList("Boolean");
Expand Down Expand Up @@ -269,7 +276,9 @@ public CoreAPI() {
new ApiAction(
ACTION_ACCESS_URL,
new String[] {PARAM_URL},
new String[] {PARAM_FOLLOW_REDIRECTS}));
new String[] {
PARAM_FOLLOW_REDIRECTS, PARAM_CONTEXT_NAME, PARAM_USER_NAME
}));
this.addApiAction(new ApiAction(ACTION_SHUTDOWN));
this.addApiAction(
new ApiAction(
Expand All @@ -296,7 +305,9 @@ public CoreAPI() {
new ApiAction(
ACTION_SEND_REQUEST,
new String[] {PARAM_REQUEST},
new String[] {PARAM_FOLLOW_REDIRECTS}));
new String[] {
PARAM_FOLLOW_REDIRECTS, PARAM_CONTEXT_NAME, PARAM_USER_NAME
}));
this.addApiAction(new ApiAction(ACTION_COLLECT_GARBAGE));
this.addApiAction(
new ApiAction(
Expand Down Expand Up @@ -431,7 +442,9 @@ public CoreAPI() {
new ApiOther(
OTHER_SEND_HAR_REQUEST,
new String[] {PARAM_REQUEST},
new String[] {PARAM_FOLLOW_REDIRECTS})));
new String[] {
PARAM_FOLLOW_REDIRECTS, PARAM_CONTEXT_NAME, PARAM_USER_NAME
})));
this.addApiOthers(new ApiOther(OTHER_FILE_DOWNLOAD, new String[] {PARAM_FILENAME}));
this.addApiOthers(
new ApiOther(
Expand Down Expand Up @@ -545,7 +558,11 @@ public ApiResponse handleApiAction(String name, JSONObject params) throws ApiExc
} catch (HttpMalformedHeaderException e) {
throw new ApiException(ApiException.Type.ILLEGAL_PARAMETER, PARAM_URL, e);
}
return sendHttpMessage(request, getParam(params, PARAM_FOLLOW_REDIRECTS, false), name);
return sendHttpMessage(
request,
getParam(params, PARAM_FOLLOW_REDIRECTS, false),
getUser(params),
name);
} else if (ACTION_SHUTDOWN.equals(name)) {
Thread thread =
new Thread("ZAP-Shutdown") {
Expand Down Expand Up @@ -771,7 +788,11 @@ public void run() {
throw new ApiException(ApiException.Type.ILLEGAL_PARAMETER, PARAM_REQUEST, e);
}
validateForCurrentMode(request);
return sendHttpMessage(request, getParam(params, PARAM_FOLLOW_REDIRECTS, false), name);
return sendHttpMessage(
request,
getParam(params, PARAM_FOLLOW_REDIRECTS, false),
getUser(params),
name);
} else if (ACTION_DELETE_ALL_ALERTS.equals(name)) {
return API.getInstance()
.getImplementors()
Expand Down Expand Up @@ -931,6 +952,36 @@ public void run() {
return ApiResponseElement.OK;
}

private static User getUser(JSONObject params) throws ApiException {
String userName = params.optString(PARAM_USER_NAME, "");
if (StringUtils.isBlank(userName)) {
return null;
}

ExtensionUserManagement usersExtension =
Control.getSingleton()
.getExtensionLoader()
.getExtension(ExtensionUserManagement.class);
if (usersExtension == null) {
throw new ApiException(Type.NO_IMPLEMENTOR, ExtensionUserManagement.NAME);
}

String contextName = params.optString(PARAM_CONTEXT_NAME, "");
if (StringUtils.isBlank(contextName)) {
throw new ApiException(Type.MISSING_PARAMETER, PARAM_CONTEXT_NAME);
}

Context context = ApiUtils.getContextByName(contextName);
List<User> users = usersExtension.getContextUserAuthManager(context.getId()).getUsers();
for (User user : users) {
if (userName.equals(user.getName())) {
return user;
}
}

throw new ApiException(Type.USER_NOT_FOUND, PARAM_USER_NAME);
}

/**
* Returns a Path for the child file underneath the specified parent directory. Detects and
* throws an exception if a path traversal attack is used.
Expand Down Expand Up @@ -1029,13 +1080,14 @@ private static boolean isValidForCurrentMode(URI uri) {
}

private ApiResponse sendHttpMessage(
HttpMessage request, boolean followRedirects, String apiResponseName)
HttpMessage request, boolean followRedirects, User user, String apiResponseName)
throws ApiException {
final ApiResponseList resultList = new ApiResponseList(apiResponseName);
try {
sendRequest(
request,
followRedirects,
user,
new Processor<HttpMessage>() {

@Override
Expand Down Expand Up @@ -1086,9 +1138,13 @@ private static HttpMessage createRequest(String request) throws HttpMalformedHea
}

private static void sendRequest(
HttpMessage request, boolean followRedirects, Processor<HttpMessage> processor)
HttpMessage request,
boolean followRedirects,
User user,
Processor<HttpMessage> processor)
throws IOException, ApiException {
HttpSender sender = new HttpSender(HttpSender.MANUAL_REQUEST_INITIATOR);
sender.setUser(user);

if (followRedirects) {
ModeRedirectionValidator redirector = new ModeRedirectionValidator(processor);
Expand Down Expand Up @@ -1508,6 +1564,7 @@ private HttpMessage handleApiOtherImpl(HttpMessage msg, String name, JSONObject
sendRequest(
request,
followRedirects,
getUser(params),
httpMessage -> {
HistoryReference hRef = httpMessage.getHistoryRef();
entries.addEntry(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1314,8 +1314,10 @@ copy.copy.popup = Copy
copy.desc = Provides a right click option to copy highlighted text

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'.
core.api.action.accessUrl.param.contextName = The user's context, ignored if the user name is not provided.
core.api.action.accessUrl.param.followRedirects =
core.api.action.accessUrl.param.url =
core.api.action.accessUrl.param.userName = The name of the user to access the URL with.
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).
core.api.action.addProxyChainExcludedDomain.param.isEnabled =
core.api.action.addProxyChainExcludedDomain.param.isRegex =
Expand Down Expand Up @@ -1357,8 +1359,10 @@ core.api.action.saveSession = Saves the session.
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.
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").
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.
core.api.action.sendRequest.param.contextName = The user's context, ignored if the user name is not provided.
core.api.action.sendRequest.param.followRedirects =
core.api.action.sendRequest.param.request =
core.api.action.sendRequest.param.userName = The name of the user to send the request with.
core.api.action.setHomeDirectory =
core.api.action.setHomeDirectory.param.dir =
core.api.action.setLogLevel = Sets the logging level for a given logger name.
Expand Down Expand Up @@ -1430,8 +1434,10 @@ core.api.other.messagesHarById.param.ids =
core.api.other.proxy.pac =
core.api.other.rootcert = Gets the Root CA certificate used by the local proxies.
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.
core.api.other.sendHarRequest.param.contextName = The user's context, ignored if the user name is not provided.
core.api.other.sendHarRequest.param.followRedirects =
core.api.other.sendHarRequest.param.request =
core.api.other.sendHarRequest.param.userName = The name of the user to send the request with.
core.api.other.setproxy =
core.api.other.setproxy.param.proxy =
core.api.other.xmlreport = Generates a report in XML format
Expand Down
Loading