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) {