439507 - Possible timing side-channel when comparing MD5-Credentials

+ Using correct digestMismatch logic
+ Fixing test cases:
  + No longer reuses / shares directories
  + Is now Windows build/test compatible
  + No longer deleteOnExit() the test data
    (let maven clean and/or test init do that)
  + Empty directories are now verified
  + Using server.getURI() instead of URL string manipulation
This commit is contained in:
Joakim Erdfelt 2014-07-17 17:55:22 -07:00
parent e39adb337f
commit c4c8426069
5 changed files with 60 additions and 66 deletions

View File

@ -160,19 +160,19 @@ public abstract class Credential implements Serializable
digest = __md.digest();
}
if (digest == null || digest.length != _digest.length) return false;
boolean match=true;
boolean digestMismatch = false;
for (int i = 0; i < digest.length; i++)
match&=digest[i] != _digest[i];
return match;
digestMismatch |= (digest[i] != _digest[i]);
return !digestMismatch;
}
else if (credentials instanceof MD5)
{
MD5 md5 = (MD5) credentials;
if (_digest.length != md5._digest.length) return false;
boolean match=true;
boolean digestMismatch = false;
for (int i = 0; i < _digest.length; i++)
match&=(_digest[i] != md5._digest[i]);
return match;
digestMismatch |= (_digest[i] != md5._digest[i]);
return !digestMismatch;
}
else if (credentials instanceof Credential)
{

View File

@ -28,7 +28,6 @@ import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import javax.naming.NamingException;
import javax.servlet.http.HttpServletResponse;
import org.apache.derby.jdbc.EmbeddedDataSource;
@ -37,9 +36,8 @@ import org.eclipse.jetty.client.api.AuthenticationStore;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.util.BasicAuthentication;
import org.eclipse.jetty.plus.security.DataSourceLoginService;
import org.eclipse.jetty.security.JDBCLoginService;
import org.eclipse.jetty.security.LoginService;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.junit.AfterClass;
@ -58,40 +56,34 @@ public class DataSourceLoginServiceTest
private static File _dbRoot;
private static HttpClient _client;
private static String __realm = "DSRealm";
private static String _baseUrl;
private static URI _baseUri;
private static final int __cacheInterval = 200;
private static DatabaseLoginServiceTestServer _testServer;
@BeforeClass
public static void setUp() throws Exception
{
_docRoot = new File("target/test-output/docroot/");
_docRoot.mkdirs();
_docRoot.deleteOnExit();
_docRoot = MavenTestingUtils.getTargetTestingDir(DataSourceLoginServiceTest.class.getSimpleName());
FS.ensureEmpty(_docRoot);
File content = new File(_docRoot,"input.txt");
FileOutputStream out = new FileOutputStream(content);
out.write(_content.getBytes("utf-8"));
out.close();
_dbRoot = new File("target/test-output/derby");
_dbRoot = new File(_docRoot, "derby");
String dbPath = _dbRoot.getAbsolutePath();
System.setProperty("derby.system.home", dbPath);
if (_dbRoot.exists())
IO.delete(_dbRoot);
FS.ensureEmpty(_dbRoot);
_dbRoot.mkdirs();
DatabaseLoginServiceTestServer.createDB(dbPath, "src/test/resources/createdb.sql", "jdbc:derby:dstest;create=true");
File scriptFile = MavenTestingUtils.getTestResourceFile("createdb.sql");
DatabaseLoginServiceTestServer.createDB(dbPath, scriptFile, "jdbc:derby:dstest;create=true");
_testServer = new DatabaseLoginServiceTestServer();
_testServer.setResourceBase(_docRoot.getAbsolutePath());
_testServer.setLoginService(configureLoginService());
_testServer.start();
_baseUrl = _testServer.getBaseUrl();
_baseUri = _testServer.getBaseUri();
}
@AfterClass
@ -141,7 +133,7 @@ public class DataSourceLoginServiceTest
{
startClient("jetty", "jetty");
ContentResponse response = _client.GET(_baseUrl + "input.txt");
ContentResponse response = _client.GET(_baseUri.resolve("input.txt"));
assertEquals(HttpServletResponse.SC_OK,response.getStatus());
assertEquals(_content, response.getContentAsString());
@ -154,7 +146,7 @@ public class DataSourceLoginServiceTest
startClient("jetty", newpwd);
response = _client.GET(_baseUrl + "input.txt");
response = _client.GET(_baseUri.resolve("input.txt"));
assertEquals(HttpServletResponse.SC_OK,response.getStatus());
assertEquals(_content, response.getContentAsString());
@ -185,7 +177,7 @@ public class DataSourceLoginServiceTest
executor.setName(executor.getName() + "-client");
_client.setExecutor(executor);
AuthenticationStore authStore = _client.getAuthenticationStore();
authStore.addAuthentication(new BasicAuthentication(URI.create(_baseUrl), __realm, user, pwd));
authStore.addAuthentication(new BasicAuthentication(_baseUri, __realm, user, pwd));
_client.start();
}

View File

@ -25,6 +25,7 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.net.URLDecoder;
import java.sql.Connection;
import java.sql.DriverManager;
@ -43,36 +44,37 @@ import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.security.LoginService;
import org.eclipse.jetty.security.authentication.BasicAuthenticator;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.NetworkConnector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.security.Constraint;
/**
* DatabaseLoginServiceTestServer
*
*
*/
public class DatabaseLoginServiceTestServer
{
private static final Logger LOG = Log.getLogger(DatabaseLoginServiceTestServer.class);
protected Server _server;
protected static String _protocol;
protected static String _baseUrl;
protected static URI _baseUri;
protected LoginService _loginService;
protected String _resourceBase;
protected TestHandler _handler;
protected static String _requestContent;
protected static boolean createDB(String homeDir, String fileName, String dbUrl)
protected static boolean createDB(String homeDir, File scriptFile, String dbUrl)
{
File scriptFile = new File(fileName);
try (FileInputStream fileStream = new FileInputStream(scriptFile))
{
Loader.loadClass(fileStream.getClass(), "org.apache.derby.jdbc.EmbeddedDriver").newInstance();
@ -85,6 +87,7 @@ public class DatabaseLoginServiceTestServer
}
catch (Exception e)
{
LOG.warn("Unable to create EmbeddedDriver",e);
return false;
}
}
@ -116,12 +119,11 @@ public class DatabaseLoginServiceTestServer
baseRequest.setHandled(true);
File file = new File(_resourcePath, URLDecoder.decode(request.getPathInfo()));
file.getParentFile().mkdirs();
file.deleteOnExit();
FS.ensureDirExists(file.getParentFile());
out = new FileOutputStream(file);
response.setStatus(HttpServletResponse.SC_CREATED);
response.setStatus(HttpServletResponse.SC_CREATED);
}
if (baseRequest.getMethod().equals("POST"))
@ -175,8 +177,8 @@ public class DatabaseLoginServiceTestServer
{
configureServer();
_server.start();
int port = ((NetworkConnector)_server.getConnectors()[0]).getLocalPort();
_baseUrl = _protocol+"://localhost:"+port+ "/";
//_server.dumpStdErr();
_baseUri = _server.getURI();
}
public void stop() throws Exception
@ -184,9 +186,9 @@ public class DatabaseLoginServiceTestServer
_server.stop();
}
public String getBaseUrl()
public URI getBaseUri()
{
return _baseUrl;
return _baseUri;
}
public TestHandler getTestHandler()

View File

@ -38,6 +38,8 @@ import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.security.JDBCLoginService;
import org.eclipse.jetty.security.LoginService;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.junit.AfterClass;
@ -64,39 +66,38 @@ public class JdbcLoginServiceTest
private static File _docRoot;
private static HttpClient _client;
private static String __realm = "JdbcRealm";
private static String _baseUrl;
private static URI _baseUri;
private static DatabaseLoginServiceTestServer _testServer;
@BeforeClass
public static void setUp() throws Exception
{
_docRoot = new File("target/test-output/docroot/");
_docRoot.mkdirs();
_docRoot.deleteOnExit();
_docRoot = MavenTestingUtils.getTargetTestingDir(JdbcLoginServiceTest.class.getSimpleName());
FS.ensureEmpty(_docRoot);
File content = new File(_docRoot,"input.txt");
FileOutputStream out = new FileOutputStream(content);
out.write(_content.getBytes("utf-8"));
out.close();
try (FileOutputStream out = new FileOutputStream(content))
{
out.write(_content.getBytes("utf-8"));
}
File dbRoot = new File("target/test-output/derby");
File dbRoot = new File(_docRoot, "derby");
String dbPath = dbRoot.getAbsolutePath();
System.setProperty("derby.system.home", dbPath);
if (dbRoot.exists())
IO.delete(dbRoot);
FS.ensureEmpty(dbRoot);
dbRoot.mkdirs();
File scriptFile = MavenTestingUtils.getTestResourceFile("createdb.sql");
DatabaseLoginServiceTestServer.createDB(dbPath, scriptFile, "jdbc:derby:jdbcrealm;create=true");
DatabaseLoginServiceTestServer.createDB(dbPath, "src/test/resources/createdb.sql", "jdbc:derby:jdbcrealm;create=true");
LoginService loginService = new JDBCLoginService(__realm, "./src/test/resources/jdbcrealm.properties");
File jdbcRealmFile = MavenTestingUtils.getTestResourceFile("jdbcrealm.properties");
LoginService loginService = new JDBCLoginService(__realm, jdbcRealmFile.getAbsolutePath());
_testServer = new DatabaseLoginServiceTestServer();
_testServer.setResourceBase(_docRoot.getAbsolutePath());
_testServer.setLoginService(loginService);
_testServer.start();
_baseUrl = _testServer.getBaseUrl();
_baseUri = _testServer.getBaseUri();
}
@AfterClass
@ -117,7 +118,7 @@ public class JdbcLoginServiceTest
{
startClient();
Request request = _client.newRequest(_baseUrl + "output.txt");
Request request = _client.newRequest(_baseUri.resolve("output.txt"));
request.method(HttpMethod.PUT);
request.content(new BytesContentProvider(_content.getBytes()));
ContentResponse response = request.send();
@ -140,7 +141,7 @@ public class JdbcLoginServiceTest
{
startClient();
ContentResponse response = _client.GET(_baseUrl + "input.txt");
ContentResponse response = _client.GET(_baseUri.resolve("input.txt"));
assertEquals(HttpServletResponse.SC_OK,response.getStatus());
assertEquals(_content, response.getContentAsString());
}
@ -158,7 +159,7 @@ public class JdbcLoginServiceTest
{
startClient();
Request request = _client.newRequest(_baseUrl + "input.txt");
Request request = _client.newRequest(_baseUri.resolve("input.txt"));
request.method(HttpMethod.HEAD);
ContentResponse response = request.send();
int responseStatus = response.getStatus();
@ -177,7 +178,7 @@ public class JdbcLoginServiceTest
{
startClient();
Request request = _client.newRequest(_baseUrl + "test");
Request request = _client.newRequest(_baseUri.resolve("test"));
request.method(HttpMethod.POST);
request.content(new BytesContentProvider(_content.getBytes()));
ContentResponse response = request.send();
@ -198,7 +199,7 @@ public class JdbcLoginServiceTest
executor.setName(executor.getName() + "-client");
_client.setExecutor(executor);
AuthenticationStore authStore = _client.getAuthenticationStore();
authStore.addAuthentication(new BasicAuthentication(URI.create(_baseUrl), __realm, "jetty", "jetty"));
authStore.addAuthentication(new BasicAuthentication(_baseUri, __realm, "jetty", "jetty"));
_client.start();
}
@ -212,17 +213,13 @@ public class JdbcLoginServiceTest
}
}
protected HttpClient getClient()
{
return _client;
}
protected String getContent()
{
return _content;
}
}

View File

@ -0,0 +1,3 @@
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
#org.eclipse.jetty.LEVEL=DEBUG
#org.eclipse.jetty.server.LEVEL=DEBUG