Skip to content

Commit

Permalink
Revert "Security: don't call prepare index for reads (elastic#34246)"
Browse files Browse the repository at this point in the history
This reverts commit 0b4e8db as some
issues have been identified with the changed handling of a primary
shard of the security index not being available.
  • Loading branch information
jaymode committed Oct 17, 2018
1 parent 18aa1c1 commit 46c7b5e
Show file tree
Hide file tree
Showing 12 changed files with 207 additions and 346 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -118,15 +118,16 @@ public void getUsers(String[] userNames, final ActionListener<Collection<User>>
}
};

if (securityIndex.isAvailable() == false) {
if (securityIndex.indexExists() == false) {
// TODO remove this short circuiting and fix tests that fail without this!
listener.onResponse(Collections.emptyList());
} else if (userNames.length == 1) { // optimization for single user lookup
final String username = userNames[0];
getUserAndPassword(username, ActionListener.wrap(
(uap) -> listener.onResponse(uap == null ? Collections.emptyList() : Collections.singletonList(uap.user())),
handleException));
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () -> {
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
final QueryBuilder query;
if (userNames == null || userNames.length == 0) {
query = QueryBuilders.termQuery(Fields.TYPE.getPreferredName(), USER_DOC_TYPE);
Expand Down Expand Up @@ -154,10 +155,10 @@ public void getUsers(String[] userNames, final ActionListener<Collection<User>>
}

void getUserCount(final ActionListener<Long> listener) {
if (securityIndex.isAvailable() == false) {
if (securityIndex.indexExists() == false) {
listener.onResponse(0L);
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () ->
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareSearch(SECURITY_INDEX_NAME)
.setQuery(QueryBuilders.termQuery(Fields.TYPE.getPreferredName(), USER_DOC_TYPE))
Expand All @@ -181,10 +182,11 @@ public void onFailure(Exception e) {
* Async method to retrieve a user and their password
*/
private void getUserAndPassword(final String user, final ActionListener<UserAndPassword> listener) {
if (securityIndex.isAvailable() == false) {
if (securityIndex.indexExists() == false) {
// TODO remove this short circuiting and fix tests that fail without this!
listener.onResponse(null);
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () ->
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareGet(SECURITY_INDEX_NAME,
INDEX_TYPE, getIdForUser(USER_DOC_TYPE, user)).request(),
Expand Down Expand Up @@ -457,28 +459,24 @@ public void onFailure(Exception e) {
}

public void deleteUser(final DeleteUserRequest deleteUserRequest, final ActionListener<Boolean> listener) {
if (securityIndex.isAvailable() == false) {
listener.onResponse(false);
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () -> {
DeleteRequest request = client.prepareDelete(SECURITY_INDEX_NAME,
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () -> {
DeleteRequest request = client.prepareDelete(SECURITY_INDEX_NAME,
INDEX_TYPE, getIdForUser(USER_DOC_TYPE, deleteUserRequest.username())).request();
request.setRefreshPolicy(deleteUserRequest.getRefreshPolicy());
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, request,
request.setRefreshPolicy(deleteUserRequest.getRefreshPolicy());
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN, request,
new ActionListener<DeleteResponse>() {
@Override
public void onResponse(DeleteResponse deleteResponse) {
clearRealmCache(deleteUserRequest.username(), listener,
deleteResponse.getResult() == DocWriteResponse.Result.DELETED);
deleteResponse.getResult() == DocWriteResponse.Result.DELETED);
}

@Override
public void onFailure(Exception e) {
listener.onFailure(e);
}
}, client::delete);
});
}
});
}

/**
Expand All @@ -500,10 +498,11 @@ void verifyPassword(String username, final SecureString password, ActionListener
}

void getReservedUserInfo(String username, ActionListener<ReservedUserInfo> listener) {
if (securityIndex.isAvailable() == false) {
if (securityIndex.indexExists() == false) {
// TODO remove this short circuiting and fix tests that fail without this!
listener.onResponse(null);
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () ->
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareGet(SECURITY_INDEX_NAME, INDEX_TYPE,
getIdForUser(RESERVED_USER_TYPE, username)).request(),
Expand Down Expand Up @@ -542,53 +541,49 @@ public void onFailure(Exception e) {
}

void getAllReservedUserInfo(ActionListener<Map<String, ReservedUserInfo>> listener) {
if (securityIndex.isAvailable() == false) {
listener.onResponse(Collections.emptyMap());
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () ->
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareSearch(SECURITY_INDEX_NAME)
securityIndex.prepareIndexIfNeededThenExecute(listener::onFailure, () ->
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareSearch(SECURITY_INDEX_NAME)
.setQuery(QueryBuilders.termQuery(Fields.TYPE.getPreferredName(), RESERVED_USER_TYPE))
.setFetchSource(true).request(),
new ActionListener<SearchResponse>() {
@Override
public void onResponse(SearchResponse searchResponse) {
Map<String, ReservedUserInfo> userInfos = new HashMap<>();
assert searchResponse.getHits().getTotalHits() <= 10 :
new ActionListener<SearchResponse>() {
@Override
public void onResponse(SearchResponse searchResponse) {
Map<String, ReservedUserInfo> userInfos = new HashMap<>();
assert searchResponse.getHits().getTotalHits() <= 10 :
"there are more than 10 reserved users we need to change this to retrieve them all!";
for (SearchHit searchHit : searchResponse.getHits().getHits()) {
Map<String, Object> sourceMap = searchHit.getSourceAsMap();
String password = (String) sourceMap.get(Fields.PASSWORD.getPreferredName());
Boolean enabled = (Boolean) sourceMap.get(Fields.ENABLED.getPreferredName());
final String id = searchHit.getId();
assert id != null && id.startsWith(RESERVED_USER_TYPE) :
for (SearchHit searchHit : searchResponse.getHits().getHits()) {
Map<String, Object> sourceMap = searchHit.getSourceAsMap();
String password = (String) sourceMap.get(Fields.PASSWORD.getPreferredName());
Boolean enabled = (Boolean) sourceMap.get(Fields.ENABLED.getPreferredName());
final String id = searchHit.getId();
assert id != null && id.startsWith(RESERVED_USER_TYPE) :
"id [" + id + "] does not start with reserved-user prefix";
final String username = id.substring(RESERVED_USER_TYPE.length() + 1);
if (password == null) {
listener.onFailure(new IllegalStateException("password hash must not be null!"));
return;
} else if (enabled == null) {
listener.onFailure(new IllegalStateException("enabled must not be null!"));
return;
} else {
userInfos.put(username, new ReservedUserInfo(password.toCharArray(), enabled, false));
}
final String username = id.substring(RESERVED_USER_TYPE.length() + 1);
if (password == null) {
listener.onFailure(new IllegalStateException("password hash must not be null!"));
return;
} else if (enabled == null) {
listener.onFailure(new IllegalStateException("enabled must not be null!"));
return;
} else {
userInfos.put(username, new ReservedUserInfo(password.toCharArray(), enabled, false));
}
listener.onResponse(userInfos);
}
listener.onResponse(userInfos);
}

@Override
public void onFailure(Exception e) {
if (e instanceof IndexNotFoundException) {
logger.trace("could not retrieve built in users since security index does not exist", e);
listener.onResponse(Collections.emptyMap());
} else {
logger.error("failed to retrieve built in users", e);
listener.onFailure(e);
}
@Override
public void onFailure(Exception e) {
if (e instanceof IndexNotFoundException) {
logger.trace("could not retrieve built in users since security index does not exist", e);
listener.onResponse(Collections.emptyMap());
} else {
logger.error("failed to retrieve built in users", e);
listener.onFailure(e);
}
}, client::search));
}
}
}, client::search));
}

private <Response> void clearRealmCache(String username, ActionListener<Response> listener, Response response) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,32 +220,32 @@ public void onFailure(Exception e) {
});
}

private void innerDeleteMapping(DeleteRoleMappingRequest request, ActionListener<Boolean> listener) {
if (securityIndex.isAvailable() == false) {
listener.onResponse(false);
} else {
securityIndex.checkIndexVersionThenExecute(listener::onFailure, () -> {
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareDelete(SECURITY_INDEX_NAME, SECURITY_GENERIC_TYPE, getIdForName(request.getName()))
private void innerDeleteMapping(DeleteRoleMappingRequest request, ActionListener<Boolean> listener) throws IOException {
if (securityIndex.isIndexUpToDate() == false) {
listener.onFailure(new IllegalStateException(
"Security index is not on the current version - the native realm will not be operational until " +
"the upgrade API is run on the security index"));
return;
}
executeAsyncWithOrigin(client.threadPool().getThreadContext(), SECURITY_ORIGIN,
client.prepareDelete(SECURITY_INDEX_NAME, SECURITY_GENERIC_TYPE, getIdForName(request.getName()))
.setRefreshPolicy(request.getRefreshPolicy())
.request(),
new ActionListener<DeleteResponse>() {
new ActionListener<DeleteResponse>() {

@Override
public void onResponse(DeleteResponse deleteResponse) {
boolean deleted = deleteResponse.getResult() == DELETED;
listener.onResponse(deleted);
}
@Override
public void onResponse(DeleteResponse deleteResponse) {
boolean deleted = deleteResponse.getResult() == DELETED;
listener.onResponse(deleted);
}

@Override
public void onFailure(Exception e) {
logger.error(new ParameterizedMessage("failed to delete role-mapping [{}]", request.getName()), e);
listener.onFailure(e);
@Override
public void onFailure(Exception e) {
logger.error(new ParameterizedMessage("failed to delete role-mapping [{}]", request.getName()), e);
listener.onFailure(e);

}
}, client::delete);
});
}
}
}, client::delete);
}

/**
Expand Down Expand Up @@ -301,7 +301,7 @@ private void getMappings(ActionListener<List<ExpressionRoleMapping>> listener) {
* </ul>
*/
public void usageStats(ActionListener<Map<String, Object>> listener) {
if (securityIndex.isAvailable() == false) {
if (securityIndex.indexExists() == false) {
reportStats(listener, Collections.emptyList());
} else {
getMappings(ActionListener.wrap(mappings -> reportStats(listener, mappings), listener::onFailure));
Expand Down
Loading

0 comments on commit 46c7b5e

Please sign in to comment.