Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

securityadmin: Replace TransportClient by RestHighLevelClient #1638

Merged
merged 6 commits into from
Mar 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
import org.opensearch.security.dlic.rest.api.SecurityRestApiActions;
import org.opensearch.security.filter.SecurityRestFilter;
import org.opensearch.security.http.SecurityHttpServerTransport;
import org.opensearch.security.rest.SecurityConfigUpdateAction;
import org.opensearch.security.rest.SecurityWhoAmIAction;
import org.opensearch.security.ssl.OpenSearchSecuritySSLPlugin;
import org.opensearch.security.ssl.rest.SecuritySSLReloadCertsAction;
import org.opensearch.security.ssl.rest.SecuritySSLCertsInfoAction;
Expand Down Expand Up @@ -459,7 +461,8 @@ public List<RestHandler> getRestHandlers(Settings settings, RestController restC
handlers.add(new DashboardsInfoAction(settings, restController, Objects.requireNonNull(evaluator), Objects.requireNonNull(threadPool)));
handlers.add(new TenantInfoAction(settings, restController, Objects.requireNonNull(evaluator), Objects.requireNonNull(threadPool),
Objects.requireNonNull(cs), Objects.requireNonNull(adminDns), Objects.requireNonNull(cr)));

handlers.add(new SecurityConfigUpdateAction(settings, restController,Objects.requireNonNull(threadPool), adminDns, configPath, principalExtractor));
handlers.add(new SecurityWhoAmIAction(settings ,restController,Objects.requireNonNull(threadPool), adminDns, configPath, principalExtractor));
cliu123 marked this conversation as resolved.
Show resolved Hide resolved
if (sslCertReloadEnabled) {
handlers.add(new SecuritySSLReloadCertsAction(settings, restController, sks, Objects.requireNonNull(threadPool), Objects.requireNonNull(adminDns)));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@
import org.opensearch.cluster.node.DiscoveryNode;
import org.opensearch.common.io.stream.StreamInput;
import org.opensearch.common.io.stream.StreamOutput;
import org.opensearch.common.xcontent.ToXContentObject;
import org.opensearch.common.xcontent.XContentBuilder;

public class ConfigUpdateNodeResponse extends BaseNodeResponse {
public class ConfigUpdateNodeResponse extends BaseNodeResponse implements ToXContentObject {

private String[] updatedConfigTypes;
private String message;
Expand Down Expand Up @@ -78,4 +80,14 @@ public void writeTo(StreamOutput out) throws IOException {
public String toString() {
return "ConfigUpdateNodeResponse [updatedConfigTypes=" + Arrays.toString(updatedConfigTypes) + ", message=" + message + "]";
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
cliu123 marked this conversation as resolved.
Show resolved Hide resolved
builder.startObject();
builder.field("updated_config_types", updatedConfigTypes);
builder.field("updated_config_size", updatedConfigTypes == null ? 0: updatedConfigTypes.length);
peternied marked this conversation as resolved.
Show resolved Hide resolved
builder.field("message", message);
builder.endObject();
return builder;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@
import org.opensearch.cluster.ClusterName;
import org.opensearch.common.io.stream.StreamInput;
import org.opensearch.common.io.stream.StreamOutput;
import org.opensearch.common.xcontent.ToXContentObject;
import org.opensearch.common.xcontent.XContentBuilder;

public class ConfigUpdateResponse extends BaseNodesResponse<ConfigUpdateNodeResponse> {
public class ConfigUpdateResponse extends BaseNodesResponse<ConfigUpdateNodeResponse> implements ToXContentObject {

public ConfigUpdateResponse(StreamInput in) throws IOException {
super(in);
}

public ConfigUpdateResponse(final ClusterName clusterName, List<ConfigUpdateNodeResponse> nodes, List<FailedNodeException> failures) {
super(clusterName, nodes, failures);
}
Expand All @@ -58,4 +60,16 @@ public List<ConfigUpdateNodeResponse> readNodesFrom(final StreamInput in) throws
public void writeNodesTo(final StreamOutput out, List<ConfigUpdateNodeResponse> nodes) throws IOException {
out.writeList(nodes);
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject("configupdate_response");
peternied marked this conversation as resolved.
Show resolved Hide resolved
builder.field("nodes", getNodesMap());
builder.field("node_size", getNodes().size());
builder.field("has_failures", hasFailures());
builder.field("failures_size", failures().size());
builder.endObject();

return builder;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ public class SecurityRestFilter {
private WhitelistingSettings whitelistingSettings;

private static final String HEALTH_SUFFIX = "health";
private static final String WHO_AM_I_SUFFIX = "whoami";

private static final String REGEX_PATH_PREFIX = "/("+ LEGACY_OPENDISTRO_PREFIX + "|" + PLUGINS_PREFIX + ")/" +"(.*)";
private static final Pattern PATTERN_PATH_PREFIX = Pattern.compile(REGEX_PATH_PREFIX);

Expand Down Expand Up @@ -184,7 +186,9 @@ private boolean checkAndAuthenticateRequest(RestRequest request, RestChannel cha

Matcher matcher = PATTERN_PATH_PREFIX.matcher(request.path());
final String suffix = matcher.matches() ? matcher.group(2) : null;
if(request.method() != Method.OPTIONS && !(HEALTH_SUFFIX.equals(suffix))) {
if(request.method() != Method.OPTIONS
&& !(HEALTH_SUFFIX.equals(suffix))
&& !(WHO_AM_I_SUFFIX.equals(suffix))) {
cliu123 marked this conversation as resolved.
Show resolved Hide resolved
if (!registry.authenticate(request, channel, threadContext)) {
// another roundtrip
org.apache.logging.log4j.ThreadContext.remove("user");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.security.rest;

import com.google.common.collect.ImmutableList;
import org.opensearch.client.node.NodeClient;
import org.opensearch.common.settings.Settings;
import org.opensearch.common.util.concurrent.ThreadContext;
import org.opensearch.rest.*;
import org.opensearch.rest.action.RestActions.NodesResponseRestListener;
import org.opensearch.security.action.configupdate.ConfigUpdateAction;
import org.opensearch.security.action.configupdate.ConfigUpdateRequest;
import org.opensearch.security.configuration.AdminDNs;
import org.opensearch.security.ssl.transport.PrincipalExtractor;
import org.opensearch.security.ssl.util.SSLRequestHelper;
import org.opensearch.security.support.ConfigConstants;
import org.opensearch.security.user.User;
import org.opensearch.threadpool.ThreadPool;

import java.io.IOException;
import java.nio.file.Path;
import java.util.List;

import static org.opensearch.rest.RestRequest.Method.PUT;
import static org.opensearch.security.dlic.rest.support.Utils.addRoutesPrefix;

public class SecurityConfigUpdateAction extends BaseRestHandler {

private static final List<Route> routes = addRoutesPrefix(ImmutableList.of(
new Route(PUT, "/configupdate")),
cliu123 marked this conversation as resolved.
Show resolved Hide resolved
"/_plugins/_security");

private final ThreadContext threadContext;
private final AdminDNs adminDns;
private final Settings settings;
private final Path configPath;
private final PrincipalExtractor principalExtractor;

public SecurityConfigUpdateAction(final Settings settings, final RestController controller, final ThreadPool threadPool, final AdminDNs adminDns,
Path configPath, PrincipalExtractor principalExtractor) {
super();
this.threadContext = threadPool.getThreadContext();
this.adminDns = adminDns;
this.settings = settings;
this.configPath = configPath;
this.principalExtractor = principalExtractor;
}

@Override public List<Route> routes() {
return routes;
}

@Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
String[] configTypes = request.paramAsStringArrayOrEmptyIfAll("config_types");

SSLRequestHelper.SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, request, principalExtractor);

if (sslInfo == null) {
return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.FORBIDDEN, ""));
}

final User user = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER);

//only allowed for admins
if (user == null || !adminDns.isAdmin(user)) {
return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.FORBIDDEN, ""));
} else {
ConfigUpdateRequest configUpdateRequest = new ConfigUpdateRequest(configTypes);
return channel -> {
client.execute(ConfigUpdateAction.INSTANCE, configUpdateRequest, new NodesResponseRestListener<>(channel));
};
}
}

@Override public String getName() {
return "Security config update";
}

}
121 changes: 121 additions & 0 deletions src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.security.rest;

import com.google.common.collect.ImmutableList;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.opensearch.client.node.NodeClient;
import org.opensearch.common.settings.Settings;
import org.opensearch.common.xcontent.XContentBuilder;
import org.opensearch.rest.BaseRestHandler;
import org.opensearch.rest.BytesRestResponse;
import org.opensearch.rest.RestChannel;
import org.opensearch.rest.RestController;
import org.opensearch.rest.RestRequest;
import org.opensearch.rest.RestStatus;
import org.opensearch.security.configuration.AdminDNs;
import org.opensearch.security.ssl.transport.PrincipalExtractor;
import org.opensearch.security.ssl.util.SSLRequestHelper;
import org.opensearch.security.ssl.util.SSLRequestHelper.SSLInfo;
import org.opensearch.security.support.ConfigConstants;
import org.opensearch.security.support.WildcardMatcher;
import org.opensearch.threadpool.ThreadPool;

import java.io.IOException;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;

import static org.opensearch.rest.RestRequest.Method.GET;
import static org.opensearch.rest.RestRequest.Method.POST;
import static org.opensearch.security.dlic.rest.support.Utils.addRoutesPrefix;


public class SecurityWhoAmIAction extends BaseRestHandler {
cliu123 marked this conversation as resolved.
Show resolved Hide resolved

private static final List<Route> routes = addRoutesPrefix(ImmutableList.of(
new Route(GET, "/whoami"),
new Route(POST, "/whoami")),
"/_plugins/_security");

private final Logger log = LogManager.getLogger(this.getClass());
private final AdminDNs adminDns;
private final Settings settings;
private final Path configPath;
private final PrincipalExtractor principalExtractor;
private final List<String> nodesDn ;

public SecurityWhoAmIAction(final Settings settings, final RestController controller,
final ThreadPool threadPool, final AdminDNs adminDns, Path configPath, PrincipalExtractor principalExtractor) {
super();
this.adminDns = adminDns;
this.settings = settings;
this.configPath = configPath;
this.principalExtractor = principalExtractor;

nodesDn = settings.getAsList(ConfigConstants.SECURITY_NODES_DN, Collections.emptyList());
}

@Override
public List<Route> routes() {
return routes;
}

@Override
protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
return new RestChannelConsumer() {

@Override
public void accept(RestChannel channel) throws Exception {
XContentBuilder builder = channel.newBuilder();
BytesRestResponse response = null;

try {

SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, request, principalExtractor);

if(sslInfo == null) {
response = new BytesRestResponse(RestStatus.FORBIDDEN, "No security data");
} else {

final String dn = sslInfo.getPrincipal();
final boolean isAdmin = adminDns.isAdminDN(dn);
final boolean isNodeCertificateRequest = dn != null && WildcardMatcher.from(nodesDn, true).matchAny(dn);

builder.startObject();
builder.field("dn", dn);
builder.field("is_admin", isAdmin);
builder.field("is_node_certificate_request", isNodeCertificateRequest);
builder.endObject();

response = new BytesRestResponse(RestStatus.OK, builder);

}
} catch (final Exception e1) {
log.error(e1.toString(), e1);
builder = channel.newBuilder();
builder.startObject();
builder.field("error", e1.toString());
builder.endObject();
response = new BytesRestResponse(RestStatus.INTERNAL_SERVER_ERROR, builder);
} finally {
if (builder != null) {
builder.close();
}
}

channel.sendResponse(response);
}
};
}

@Override
public String getName() {
return "Security Plugin Who am i";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ public boolean matchAny(Collection<String> candidates) {
return matchAny(candidates.stream());
}

public boolean matchAny(String[] candidates) {
cliu123 marked this conversation as resolved.
Show resolved Hide resolved
public boolean matchAny(String... candidates) {
return matchAny(Arrays.stream(candidates));
}

Expand Down
Loading