/*
* Zed Attack Proxy (ZAP) and its related class files.
*
* ZAP is an HTTP/HTTPS proxy for assessing web application security.
*
* Copyright 2017 The ZAP development team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.zaproxy.zap.extension.api;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import java.net.Inet4Address;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.apache.log4j.varia.NullAppender;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.parosproxy.paros.network.HttpInputStream;
import org.parosproxy.paros.network.HttpMessage;
import org.parosproxy.paros.network.HttpOutputStream;
import org.parosproxy.paros.network.HttpRequestHeader;
import org.parosproxy.paros.view.View;
import org.zaproxy.zap.network.DomainMatcher;
import org.zaproxy.zap.utils.ZapXmlConfiguration;
import net.sf.json.JSONObject;
/**
* Unit test for {@link API}.
*/
@RunWith(MockitoJUnitRunner.class)
public class APIUnitTest {
@BeforeClass
public static void setUp() throws Exception {
Logger.getRootLogger().addAppender(new NullAppender());
}
@Test
public void shouldBeEnabledWhenInDaemonMode() {
// Given
API api = new API();
// When
View.setDaemon(true);
// Then
assertThat(api.isEnabled(), is(equalTo(true)));
}
@Test
public void shouldDenyAllAddressesIfNoneSet() throws Exception {
// Given
API api = new API();
api.setOptionsParamApi(new OptionsParamApi());
TestApiImplementor apiImplementor = new TestApiImplementor();
String requestUri = api.getCallBackUrl(apiImplementor, "http://example.com");
// When
boolean requestHandled = api.handleApiRequest(
createApiRequest(new byte[] { 127, 0, 0, 1 }, "example.com", requestUri),
createMockedHttpInputStream(),
createMockedHttpOutputStream());
// Then
assertThat(requestHandled, is(equalTo(true)));
assertThat(apiImplementor.wasUsed(), is(equalTo(false)));
}
@Test
public void shouldDenyAddressNotSet() throws Exception {
// Given
API api = new API();
OptionsParamApi apiOptions = new OptionsParamApi();
apiOptions.load(new ZapXmlConfiguration());
apiOptions.setPermittedAddresses(createPermittedAddresses("127.0.0.1"));
api.setOptionsParamApi(apiOptions);
TestApiImplementor apiImplementor = new TestApiImplementor();
String requestUri = api.getCallBackUrl(apiImplementor, "http://example.com");
// When
boolean requestHandled = api.handleApiRequest(
createApiRequest(new byte[] { 10, 0, 0, 2 }, "example.com", requestUri),
createMockedHttpInputStream(),
createMockedHttpOutputStream());
// Then
assertThat(requestHandled, is(equalTo(true)));
assertThat(apiImplementor.wasUsed(), is(equalTo(false)));
}
@Test
public void shouldDenyHostnameNotSet() throws Exception {
// Given
API api = new API();
OptionsParamApi apiOptions = new OptionsParamApi();
apiOptions.load(new ZapXmlConfiguration());
apiOptions.setPermittedAddresses(createPermittedAddresses("127.0.0.1", "localhost"));
api.setOptionsParamApi(apiOptions);
TestApiImplementor apiImplementor = new TestApiImplementor();
String requestUri = api.getCallBackUrl(apiImplementor, "http://example.com");
// When
boolean requestHandled = api.handleApiRequest(
createApiRequest(new byte[] { 127, 0, 0, 1 }, "example.com", requestUri),
createMockedHttpInputStream(),
createMockedHttpOutputStream());
// Then
assertThat(requestHandled, is(equalTo(true)));
assertThat(apiImplementor.wasUsed(), is(equalTo(false)));
}
@Test
public void shouldAcceptAddressAndHostnameSet() throws Exception {
// Given
API api = new API();
OptionsParamApi apiOptions = new OptionsParamApi();
apiOptions.load(new ZapXmlConfiguration());
apiOptions.setPermittedAddresses(createPermittedAddresses("10.0.0.8", "example.com"));
api.setOptionsParamApi(apiOptions);
TestApiImplementor apiImplementor = new TestApiImplementor();
String requestUri = api.getCallBackUrl(apiImplementor, "http://example.com");
// When
boolean requestHandled = api.handleApiRequest(
createApiRequest(new byte[] { 10, 0, 0, 8 }, "example.com", requestUri),
createMockedHttpInputStream(),
createMockedHttpOutputStream());
// Then
assertThat(requestHandled, is(equalTo(true)));
assertThat(apiImplementor.wasUsed(), is(equalTo(true)));
}
private List<DomainMatcher> createPermittedAddresses(String... addresses) {
if (addresses == null || addresses.length == 0) {
return new ArrayList<>();
}
List<DomainMatcher> permittedAddresses = new ArrayList<>();
for (String address : addresses) {
permittedAddresses.add(new DomainMatcher(address));
}
return permittedAddresses;
}
private HttpRequestHeader createApiRequest(byte[] remoteAddress, String hostname, String requestUri) throws Exception {
HttpRequestHeader httpRequestHeader = new HttpRequestHeader(
"GET " + requestUri + " HTTP/1.1\r\n" + "Host: " + hostname + "\r\n");
httpRequestHeader.setSenderAddress(Inet4Address.getByAddress(remoteAddress));
return httpRequestHeader;
}
private HttpInputStream createMockedHttpInputStream() {
return Mockito.mock(HttpInputStream.class);
}
private HttpOutputStream createMockedHttpOutputStream() {
return Mockito.mock(HttpOutputStream.class);
}
private static class TestApiImplementor extends ApiImplementor {
public static final String PREFIX = "test";
private boolean used;
@Override
public String getPrefix() {
return PREFIX;
}
@Override
public ApiResponse handleApiView(String name, JSONObject params) throws ApiException {
used = true;
return new ApiResponseElement(name);
}
@Override
public ApiResponse handleApiAction(String name, JSONObject params) throws ApiException {
used = true;
return new ApiResponseElement(name);
}
@Override
public HttpMessage handleApiOther(HttpMessage msg, String name, JSONObject params) throws ApiException {
used = true;
return new HttpMessage();
}
@Override
public String handleCallBack(HttpMessage msg) throws ApiException {
used = true;
return "response";
}
@Override
public ApiResponse handleApiOptionView(String name, JSONObject params) throws ApiException {
used = true;
return new ApiResponseElement(name);
}
@Override
public ApiResponse handleApiOptionAction(String name, JSONObject params) throws ApiException {
used = true;
return new ApiResponseElement(name);
}
@Override
public HttpMessage handleShortcut(HttpMessage msg) throws ApiException {
used = true;
return new HttpMessage();
}
public boolean wasUsed() {
return used;
}
}
}