/**
* Copyright (C) 2009-2014 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.foundationdb.http;
import com.foundationdb.rest.RestService;
import com.foundationdb.rest.RestServiceImpl;
import com.foundationdb.server.service.servicemanager.GuicedServiceManager;
import com.foundationdb.server.test.it.ITBase;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpOptions;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.hamcrest.CoreMatchers.containsString;
public abstract class CsrfProtectionITBase extends RestServiceITBase
{
protected abstract String getUserInfo();
@Override
protected Map<String,String> startupConfigProperties() {
Map<String,String> config = new HashMap<>(super.startupConfigProperties());
config.put("fdbsql.http.csrf_protection.allowed_referers", "http://somewhere.com,https://coolest.site.edu:4320");
return config;
}
@Test
public void requestBlockedWithMissingReferer() throws Exception{
HttpUriRequest request = new HttpPut(defaultURI());
response = client.execute(request);
assertEquals("status", HttpStatus.SC_FORBIDDEN, response.getStatusLine().getStatusCode());
assertThat("reason", response.getStatusLine().getReasonPhrase(), containsString("Referer"));
}
@Test
public void requestBlockedWithEmptyReferer() throws Exception{
HttpUriRequest request = new HttpPut(defaultURI());
request.setHeader("Referer","");
response = client.execute(request);
assertEquals("status", HttpStatus.SC_FORBIDDEN, response.getStatusLine().getStatusCode());
assertThat("reason", response.getStatusLine().getReasonPhrase(), containsString("Referer"));
}
@Test
public void getBlockedWithBadHost() throws Exception{
// Although we let blank & empty referers through for get requests, there is no benefit to
// letting incorrect referers through, so those are always blocked.
HttpUriRequest request = new HttpGet(defaultURI());
request.setHeader("Referer", "https://coolest.site.edu.fake.com:4320");
response = client.execute(request);
assertEquals("status", HttpStatus.SC_FORBIDDEN, response.getStatusLine().getStatusCode());
assertThat("reason", response.getStatusLine().getReasonPhrase(), containsString("Referer"));
}
@Test
public void postBlockedWithBadHost() throws Exception{
HttpUriRequest request = new HttpPost(defaultURI());
request.setHeader("Referer", "https://coolest.site.edu.fake.com:4320");
response = client.execute(request);
assertEquals("status", HttpStatus.SC_FORBIDDEN, response.getStatusLine().getStatusCode());
assertThat("reason", response.getStatusLine().getReasonPhrase(), containsString("Referer"));
}
@Test
public void putBlockedWithMissingReferer() throws Exception{
HttpUriRequest request = new HttpPut(defaultURI());
response = client.execute(request);
assertEquals("status", HttpStatus.SC_FORBIDDEN, response.getStatusLine().getStatusCode());
assertThat("reason", response.getStatusLine().getReasonPhrase(), containsString("Referer"));
}
@Test
public void putBlockedWithBlankReferer() throws Exception{
HttpUriRequest request = new HttpPut(defaultURI());
request.setHeader("Referer","");
response = client.execute(request);
assertEquals("status", HttpStatus.SC_FORBIDDEN, response.getStatusLine().getStatusCode());
assertThat("reason", response.getStatusLine().getReasonPhrase(), containsString("Referer"));
}
@Test
public void getBlockedHasJsonResponse() throws Exception{
HttpUriRequest request = new HttpGet(defaultURI());
request.setHeader("Referer", "https://coolest.site.edu.fake.com:4320");
response = client.execute(request);
assertEquals("status", HttpStatus.SC_FORBIDDEN, response.getStatusLine().getStatusCode());
assertThat("reason", response.getStatusLine().getReasonPhrase(), containsString("Referer"));
assertThat("body", EntityUtils.toString(response.getEntity()), containsString("Referer"));
}
@Test
public void putBlockedHasJsonResponse() throws Exception{
HttpUriRequest request = new HttpPut(defaultURI());
response = client.execute(request);
assertEquals("status", HttpStatus.SC_FORBIDDEN, response.getStatusLine().getStatusCode());
assertThat("reason", response.getStatusLine().getReasonPhrase(), containsString("Referer"));
assertThat("body", EntityUtils.toString(response.getEntity()), containsString("Referer"));
}
@Test
public void patchBlockedHasJsonResponse() throws Exception{
HttpUriRequest request = new HttpPatch(defaultURI());
response = client.execute(request);
assertEquals("status", HttpStatus.SC_FORBIDDEN, response.getStatusLine().getStatusCode());
assertThat("reason", response.getStatusLine().getReasonPhrase(), containsString("Referer"));
assertThat("body", EntityUtils.toString(response.getEntity()), containsString("Referer"));
}
@Test
public void postBlockedHasJsonResponse() throws Exception{
HttpUriRequest request = new HttpPost(defaultURI());
response = client.execute(request);
assertEquals("status", HttpStatus.SC_FORBIDDEN, response.getStatusLine().getStatusCode());
assertThat("reason", response.getStatusLine().getReasonPhrase(), containsString("Referer"));
assertThat("body", EntityUtils.toString(response.getEntity()), containsString("Referer"));
}
@Test
public void deleteBlockedHasJsonResponse() throws Exception{
HttpUriRequest request = new HttpDelete(defaultURI());
response = client.execute(request);
assertEquals("status", HttpStatus.SC_FORBIDDEN, response.getStatusLine().getStatusCode());
assertThat("reason", response.getStatusLine().getReasonPhrase(), containsString("Referer"));
assertThat("body", EntityUtils.toString(response.getEntity()), containsString("Referer"));
}
@Test
public void getAllowedWithNoReferer() throws Exception{
// Since GET requests don't have side effects, the cross-origin header will prevent
// third-party javascript from viewing the result, meaning that we can allow this through.
HttpUriRequest request = new HttpGet(defaultURI());
response = client.execute(request);
assertEquals("status", HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
}
@Test
public void getAllowedWithBlankReferer() throws Exception{
// Since GET requests don't have side effects, the cross-origin header will prevent
// third-party javascript from viewing the result, meaning that we can allow this through.
HttpUriRequest request = new HttpGet(defaultURI());
request.setHeader("Referer","");
response = client.execute(request);
assertEquals("status", HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
}
@Test
public void getAllowed1() throws Exception{
HttpUriRequest request = new HttpGet(defaultURI());
request.setHeader("Referer","http://somewhere.com");
response = client.execute(request);
assertEquals("status", HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
}
@Test
public void getAllowed2() throws Exception{
HttpUriRequest request = new HttpGet(defaultURI());
request.setHeader("Referer","https://coolest.site.edu:4320");
response = client.execute(request);
assertEquals("status", HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
}
@Test
public void postAllowed() throws Exception{
HttpPost request = new HttpPost(defaultURI());
request.setHeader("Referer","http://somewhere.com");
request.setHeader("Content-Type", "application/json");
request.setEntity(new StringEntity("{\"id\": \"1\"}"));
response = client.execute(request);
assertEquals("status", HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
}
@Test
public void putAllowed() throws Exception{
HttpPut request = new HttpPut(defaultURI("/1"));
request.setHeader("Referer","http://somewhere.com");
request.setHeader("Content-Type", "application/json");
request.setEntity(new StringEntity("{\"id\": \"1\"}"));
response = client.execute(request);
assertEquals("status", HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
}
@Test
public void deleteAllowed() throws Exception{
HttpUriRequest request = new HttpDelete(defaultURI("/1"));
request.setHeader("Referer","http://somewhere.com");
response = client.execute(request);
assertEquals("status", HttpStatus.SC_NO_CONTENT, response.getStatusLine().getStatusCode());
}
}