From 1b72f134589d5008693b321f780560065035aaac Mon Sep 17 00:00:00 2001 From: jaymode Date: Wed, 5 Aug 2015 09:25:30 -0400 Subject: [PATCH] fix the rest response for the clear cache action and add tests Today the XContent building of the response for the ClearRealmsCacheResponse is broken and causes an exception to be thrown. This fixes the building of the response and adds tests that call the HTTP endpoint and do a basic check on the response. Closes elastic/elasticsearch#390 Original commit: elastic/x-pack-elasticsearch@8ad9dae4ea86048ff62fecf089640ebc77d0a936 --- shield/docs/public/managing-users.asciidoc | 5 +- .../authc/cache/ClearRealmCacheResponse.java | 2 + .../integration/ClearRealmsCacheTests.java | 155 ++++++++++++++---- 3 files changed, 126 insertions(+), 36 deletions(-) diff --git a/shield/docs/public/managing-users.asciidoc b/shield/docs/public/managing-users.asciidoc index 5f281f3b0be..3dd8077d841 100644 --- a/shield/docs/public/managing-users.asciidoc +++ b/shield/docs/public/managing-users.asciidoc @@ -230,7 +230,7 @@ describes the different hash algorithm that can be set: [float] [[cache-eviction-api]] ==== Cache Eviction API -Shield exposes an API to force cached user eviction. The following example, evicts all users from the `ldap1` +Shield exposes an API to force cached user eviction. The following example, evicts all users from the `esusers` realm: [source, java] @@ -238,6 +238,9 @@ realm: $ curl -XPOST 'http://localhost:9200/_shield/realm/esusers/_cache/clear' ------------------------------------------------------------ +NOTE: if no realm is defined, the default realm name, `default_esusers` can be used to clear the cache +of the default esusers realm. + It is also possible to evict specific users: [source, java] diff --git a/shield/src/main/java/org/elasticsearch/shield/action/authc/cache/ClearRealmCacheResponse.java b/shield/src/main/java/org/elasticsearch/shield/action/authc/cache/ClearRealmCacheResponse.java index cb48869894d..774b273f379 100644 --- a/shield/src/main/java/org/elasticsearch/shield/action/authc/cache/ClearRealmCacheResponse.java +++ b/shield/src/main/java/org/elasticsearch/shield/action/authc/cache/ClearRealmCacheResponse.java @@ -49,6 +49,7 @@ public class ClearRealmCacheResponse extends BaseNodesResponse= 0) { + assertThat(prevUser, not(sameInstance(newUser))); + } else { + assertThat(prevUser, sameInstance(newUser)); + } + } + + @Override + public void executeRequest() throws Exception { + executeTransportRequest(new ClearRealmCacheRequest().usernames(evicted_usernames)); + } + }, + + EVICT_ALL_HTTP() { + + @Override + public void assertEviction(User prevUser, User newUser) { + assertThat(prevUser, not(sameInstance(newUser))); + } + + @Override + public void executeRequest() throws Exception { + executeHttpRequest("/_shield/realm/" + (randomBoolean() ? "*" : "_all") + "/_cache/clear", Collections.emptyMap()); + } + }, + + EVICT_SOME_HTTP() { + + private final String[] evicted_usernames = randomSelection(usernames); + { + Arrays.sort(evicted_usernames); } @Override @@ -81,13 +119,76 @@ public class ClearRealmsCacheTests extends ShieldIntegTestCase { assertThat(prevUser, sameInstance(newUser)); } } + + @Override + public void executeRequest() throws Exception { + String path = "/_shield/realm/" + (randomBoolean() ? "*" : "_all") + "/_cache/clear"; + Map params = Collections.singletonMap("usernames", Joiner.on(',').join(evicted_usernames)); + executeHttpRequest(path, params); + } }; - public abstract ClearRealmCacheRequest createRequest(); - public abstract void assertEviction(User prevUser, User newUser); + + public abstract void executeRequest() throws Exception; + + static void executeTransportRequest(ClearRealmCacheRequest request) throws Exception { + ShieldClient client = new ShieldClient(client()); + + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference error = new AtomicReference<>(); + client.authc().clearRealmCache(request, new ActionListener() { + @Override + public void onResponse(ClearRealmCacheResponse response) { + assertThat(response.getNodes().length, equalTo(internalTestCluster().getNodeNames().length)); + latch.countDown(); + } + + @Override + public void onFailure(Throwable e) { + error.set(e); + latch.countDown(); + } + }); + + if (!latch.await(5, TimeUnit.SECONDS)) { + fail("waiting for clear realms cache request too long"); + } + + if (error.get() != null) { + fail("failed to clear realm caches" + error.get().getMessage()); + } + } + + static void executeHttpRequest(String path, Map params) throws Exception { + try (CloseableHttpClient client = HttpClients.createDefault()) { + HttpRequestBuilder requestBuilder = new HttpRequestBuilder(client) + .httpTransport(internalTestCluster().getDataNodeInstance(HttpServerTransport.class)) + .method("POST") + .path(path); + for (Map.Entry entry : params.entrySet()) { + requestBuilder.addParam(entry.getKey(), entry.getValue()); + } + requestBuilder.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, UsernamePasswordToken.basicAuthHeaderValue(ShieldSettingsSource.DEFAULT_USER_NAME, new SecuredString(ShieldSettingsSource.DEFAULT_PASSWORD.toCharArray()))); + HttpResponse response = requestBuilder.execute(); + assertThat(response.hasBody(), is(true)); + String body = response.getBody(); + assertThat(body.contains("cluster_name"), is(true)); + } + } } + @Override + public Settings nodeSettings(int nodeOrdinal) { + return Settings.builder() + .put(super.nodeSettings(nodeOrdinal)) + .put(Node.HTTP_ENABLED, true) + .build(); + } + @Override + public boolean sslTransportEnabled() { + return false; + } @Override protected String configRoles() { @@ -121,6 +222,16 @@ public class ClearRealmsCacheTests extends ShieldIntegTestCase { testScenario(Scenario.EVICT_SOME); } + @Test + public void testEvictAllHttp() throws Exception { + testScenario(Scenario.EVICT_ALL_HTTP); + } + + @Test + public void testEvictSomeHttp() throws Exception { + testScenario(Scenario.EVICT_SOME_HTTP); + } + private void testScenario(Scenario scenario) throws Exception { Map tokens = new HashMap<>(); @@ -158,33 +269,7 @@ public class ClearRealmsCacheTests extends ShieldIntegTestCase { } // now, lets run the scenario - - ShieldClient client = new ShieldClient(client()); - - final CountDownLatch latch = new CountDownLatch(1); - final AtomicReference error = new AtomicReference<>(); - client.authc().clearRealmCache(scenario.createRequest(), new ActionListener() { - @Override - public void onResponse(ClearRealmCacheResponse response) { - assertThat(response.getNodes().length, equalTo(internalTestCluster().getNodeNames().length)); - latch.countDown(); - } - - @Override - public void onFailure(Throwable e) { - error.set(e); - latch.countDown(); - } - }); - - if (!latch.await(5, TimeUnit.SECONDS)) { - fail("waiting for clear realms cache request too long"); - } - - if (error.get() != null) { - logger.error("failed to clear realm caches", error.get()); - fail("failed to clear realm caches"); - } + scenario.executeRequest(); // now, user_a should have been evicted, but user_b should still be cached for (String username : usernames) {