@Test public void shouldReplyNicelyToTooManyFailedAuthAttempts() throws Exception { // Given startServerWithConfiguredUser(); long timeout = System.currentTimeMillis() + 30_000; // When HTTP.Response response = null; while (System.currentTimeMillis() < timeout) { // Done in a loop because we're racing with the clock to get enough failed requests into 5 // seconds response = HTTP.withHeaders(HttpHeaders.AUTHORIZATION, challengeResponse("neo4j", "incorrect")) .POST( server.baseUri().resolve("authentication").toString(), HTTP.RawPayload.quotedJson( "{'username':'******', 'password':'******'}")); if (response.status() == 429) { break; } } // Then assertThat(response.status(), equalTo(429)); JsonNode firstError = response.get("errors").get(0); assertThat( firstError.get("code").asText(), equalTo("Neo.ClientError.Security.AuthenticationRateLimit")); assertThat( firstError.get("message").asText(), equalTo("Too many failed authentication requests. Please wait 5 seconds and try again.")); }
private void assertAuthorizationRequired( String method, String path, Object payload, int expectedAuthorizedStatus) throws JsonParseException { // When no header HTTP.Response response = HTTP.request(method, server.baseUri().resolve(path).toString(), payload); assertThat(response.status(), equalTo(401)); assertThat( response.get("errors").get(0).get("code").asText(), equalTo("Neo.ClientError.Security.AuthorizationFailed")); assertThat( response.get("errors").get(0).get("message").asText(), equalTo("No authorization header supplied.")); assertThat(response.header(HttpHeaders.WWW_AUTHENTICATE), equalTo("None")); // When malformed header response = HTTP.withHeaders(HttpHeaders.AUTHORIZATION, "This makes no sense") .request(method, server.baseUri().resolve(path).toString(), payload); assertThat(response.status(), equalTo(400)); assertThat( response.get("errors").get(0).get("code").asText(), equalTo("Neo.ClientError.Request.InvalidFormat")); assertThat( response.get("errors").get(0).get("message").asText(), equalTo("Invalid Authorization header.")); // When invalid credential response = HTTP.withHeaders(HttpHeaders.AUTHORIZATION, challengeResponse("neo4j", "incorrect")) .request(method, server.baseUri().resolve(path).toString(), payload); assertThat(response.status(), equalTo(401)); assertThat( response.get("errors").get(0).get("code").asText(), equalTo("Neo.ClientError.Security.AuthorizationFailed")); assertThat( response.get("errors").get(0).get("message").asText(), equalTo("Invalid username or password.")); assertThat(response.header(HttpHeaders.WWW_AUTHENTICATE), equalTo("None")); // When authorized response = HTTP.withHeaders(HttpHeaders.AUTHORIZATION, challengeResponse("neo4j", "secret")) .request(method, server.baseUri().resolve(path).toString(), payload); assertThat(response.status(), equalTo(expectedAuthorizedStatus)); }
@Test public void shouldNotAllowDataAccess() throws Exception { // Given startServerWithConfiguredUser(); // When & then assertAuthorizationRequired( "POST", "db/data/node", RawPayload.quotedJson("{'name':'jake'}"), 201); assertAuthorizationRequired("GET", "db/data/node/1234", 404); assertAuthorizationRequired( "POST", "db/data/transaction/commit", RawPayload.quotedJson("{'statements':[{'statement':'MATCH (n) RETURN n'}]}"), 200); assertEquals(200, HTTP.GET(server.baseUri().resolve("webadmin").toString()).status()); assertEquals(200, HTTP.GET(server.baseUri().resolve("browser").toString()).status()); assertEquals(200, HTTP.GET(server.baseUri().resolve("").toString()).status()); }
public void startServerWithConfiguredUser() throws IOException { startServer(true); // Set the password HTTP.Response post = HTTP.withHeaders(HttpHeaders.AUTHORIZATION, challengeResponse("neo4j", "neo4j")) .POST( server.baseUri().resolve("/user/neo4j/password").toString(), RawPayload.quotedJson("{'password':'******'}")); assertEquals(200, post.status()); }
public void startServer(boolean authEnabled) throws IOException { new File("neo4j-home/data/dbms/authorization") .delete(); // TODO: Implement a common component for managing Neo4j file structure and use // that here server = CommunityServerBuilder.server() .withProperty( ServerSettings.authorization_enabled.name(), Boolean.toString(authEnabled)) .build(); server.start(); }
@Test public void shouldAllowAllAccessIfAuthenticationIsDisabled() throws Exception { // Given startServer(false); // When & then assertEquals( 201, HTTP.POST( server.baseUri().resolve("db/data/node").toString(), RawPayload.quotedJson("{'name':'jake'}")) .status()); assertEquals(404, HTTP.GET(server.baseUri().resolve("db/data/node/1234").toString()).status()); assertEquals( 200, HTTP.POST( server.baseUri().resolve("db/data/transaction/commit").toString(), RawPayload.quotedJson("{'statements':[{'statement':'MATCH (n) RETURN n'}]}")) .status()); }
public void stop() { server.stop(); }
public ServerDoctorWhoUniverse(CommunityNeoServer server) throws Exception { this.server = server; server.start(); }
private String passwordURL(String username) { return server.baseUri().resolve("user/" + username + "/password").toString(); }
private String userURL(String username) { return server.baseUri().resolve("user/" + username).toString(); }
private String dataURL() { return server.baseUri().resolve("db/data/").toString(); }
@After public void cleanup() { if (server != null) { server.stop(); } }