Skip to content

Commit

Permalink
Blocking API calls - enabled (#976). Currently - DROP only
Browse files Browse the repository at this point in the history
  • Loading branch information
michbarsinai committed Mar 3, 2015
1 parent c391096 commit 35e748a
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 11 deletions.
4 changes: 0 additions & 4 deletions doc/sphinx-guides/source/api/native-api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,6 @@ This endopint deals with users of the built-in authentication provider. Note tha
For this service to work, the setting ``BuiltinUsers.KEY`` has to be set, and its value passed as ``key`` to
each of the calls.

List all users::

GET http://$SERVER/api/users?key=$key

Generates a new user. Data about the user are posted via JSON. *Note that the password is passed as a parameter in the query*. ::

POST http://$SERVER/api/users?password=$password&key=$key
Expand Down
6 changes: 6 additions & 0 deletions scripts/api/post-intall-api-block.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash

# Run this script post-installation, to block all the settings that
# should not be available to the general public in a production Dataverse installation.

curl -X PUT -d groups,s,index,datasetfield http://localhost:8080/api/s/settings/:BlockedApiEndpoints
2 changes: 2 additions & 0 deletions scripts/api/setup-all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,5 @@ echo

# OPTIONAL USERS AND DATAVERSES
#./setup-optional.sh

echo "Setup done. Consider running post-install-api-block.sh for blocking the sensitive API."
53 changes: 53 additions & 0 deletions scripts/api/testBlockEndpoints.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/bin/bash

ADMIN_KEY=$1

echo Testing Groups
curl http://localhost:8080/api/groups/ip/?key=$ADMIN_KEY
echo

echo blocking groups
curl -X PUT -d groups http://localhost:8080/api/s/settings/:BlockedApiEndpoints
echo

echo Testing Groups again - expecting 503 Unavailable
curl -v http://localhost:8080/api/groups/ip/?key=$ADMIN_KEY
echo

echo Unblocking groups
curl -X DELETE http://localhost:8080/api/s/settings/:BlockedApiEndpoints
echo

echo Testing Groups
curl http://localhost:8080/api/groups/ip/?key=$ADMIN_KEY
echo

echo blocking groups, Roles
curl -X PUT -d groups,roles http://localhost:8080/api/s/settings/:BlockedApiEndpoints
echo

echo Testing Groups again - expecting 503 Unavailable
curl -v http://localhost:8080/api/groups/ip/?key=$ADMIN_KEY
echo

echo Testing Roles - expecting 503 Unavailable
curl -v http://localhost:8080/api/roles/?key=$ADMIN_KEY
echo

echo blocking Roles only
curl -X PUT -d roles http://localhost:8080/api/s/settings/:BlockedApiEndpoints
echo

echo Testing Groups again
curl -v http://localhost:8080/api/groups/ip/?key=$ADMIN_KEY
echo

echo Testing Roles - expecting 503 Unavailable
curl -v http://localhost:8080/api/roles/?key=$ADMIN_KEY
echo

echo Unblocking all
curl -X DELETE http://localhost:8080/api/s/settings/:BlockedApiEndpoints
echo

echo DONE
2 changes: 0 additions & 2 deletions src/main/java/edu/harvard/iq/dataverse/api/Admin.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
import edu.harvard.iq.dataverse.authorization.providers.AuthenticationProviderRow;
import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
import edu.harvard.iq.dataverse.settings.Setting;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.json.Json;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObjectBuilder;
Expand Down
97 changes: 97 additions & 0 deletions src/main/java/edu/harvard/iq/dataverse/api/ApiBlockingFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package edu.harvard.iq.dataverse.api;

import edu.harvard.iq.dataverse.settings.SettingsServiceBean;
import java.io.IOException;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* A web filter to block API administration calls.
* @author michael
*/
@WebFilter( urlPatterns={"/api/*"} )
public class ApiBlockingFilter implements javax.servlet.Filter {

private static final Logger logger = Logger.getLogger(ApiBlockingFilter.class.getName());

@EJB
protected SettingsServiceBean settingsSvc;

final Set<String> blockedApiEndpoints = new TreeSet<>();
private String lastEndpointList;

@Override
public void init(FilterConfig fc) throws ServletException {
updateBlockedPoints();
}

private void updateBlockedPoints() {
blockedApiEndpoints.clear();
String endpointList = settingsSvc.getValueForKey(SettingsServiceBean.Key.BlockedApiEndpoints, "");
for ( String endpoint : endpointList.split(",") ) {
String endpointPrefix = canonize(endpoint);
if ( ! endpointPrefix.isEmpty() ) {
logger.log(Level.INFO, "Blocking API endpoint: {0}", endpointPrefix);
blockedApiEndpoints.add(endpointPrefix);
}
}
lastEndpointList = endpointList;
}

@Override
public void doFilter(ServletRequest sr, ServletResponse sr1, FilterChain fc) throws IOException, ServletException {
String endpointList = settingsSvc.getValueForKey(SettingsServiceBean.Key.BlockedApiEndpoints, "");
if ( ! endpointList.equals(lastEndpointList) ) {
updateBlockedPoints();
}

HttpServletRequest hsr = (HttpServletRequest) sr;
String apiEndpoint = canonize(hsr.getRequestURI().substring(hsr.getServletPath().length()));

for ( String prefix : blockedApiEndpoints ) {
if ( apiEndpoint.startsWith(prefix) ) {
// Block!
HttpServletResponse httpResponse = (HttpServletResponse) sr1;
httpResponse.getWriter().println("{ status:\"error\", message:\"Endpoint blocked. Please contact the dataverse administrator\"}" );
httpResponse.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
httpResponse.setContentType("application/json");
return;
}
}

fc.doFilter(sr, sr1);
}

@Override
public void destroy() {
logger.info("WebFilter destroy");
}

/**
* Creates a canonical representation of {@code in}: trimmed spaces and slashes
* @param in the raw string
* @return {@code in} with no trailing and leading spaces and slashes.
*/
private String canonize( String in ) {
in = in.trim();
if ( in.startsWith("/") ) {
in = in.substring(1);
}
if ( in.endsWith("/") ) {
in = in.substring(0, in.length()-1);
}
return in;
}

}
5 changes: 0 additions & 5 deletions src/main/java/edu/harvard/iq/dataverse/api/Mail.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package edu.harvard.iq.dataverse.api;

import edu.harvard.iq.dataverse.MailServiceBean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ public enum Key {
* Search API. See also https://github.com/IQSS/dataverse/issues/1299
*/
SearchApiNonPublicAllowed,

/**
* API endpoints that are not accessible. Comma separated list.
*/
BlockedApiEndpoints,

/**
* For development only (see dev guide for details). Backed by an enum
* of possible account types.
Expand Down

0 comments on commit 35e748a

Please sign in to comment.