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

Security User Refactor #2594

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
34135c6
Add extensionsManager into GuiceHolder
stephen-crawford Mar 27, 2023
a077d4b
Basic outline of functions for making service accounts
stephen-crawford Mar 27, 2023
24fb0b4
Outline of service account creation
stephen-crawford Mar 27, 2023
6a29fe5
Extension Service Outline
stephen-crawford Mar 28, 2023
2c7d0fc
Add test method names and pass through
stephen-crawford Mar 28, 2023
75800e1
add licenses and spotless
stephen-crawford Mar 28, 2023
86813f2
Test notes
stephen-crawford Mar 29, 2023
5ada6af
Update
stephen-crawford Mar 30, 2023
e8c7535
clear
stephen-crawford Mar 31, 2023
989cafd
Merge branch 'opensearch-project:main' into ServiceAccounts
stephen-crawford Mar 31, 2023
84036a4
remove unused import
stephen-crawford Mar 31, 2023
4e4582b
Remove imports
stephen-crawford Mar 31, 2023
f723f30
Remove import *
stephen-crawford Mar 31, 2023
389287a
Checkstyle
stephen-crawford Mar 31, 2023
49ef438
Comment out test
stephen-crawford Apr 3, 2023
fa8af78
spotless
stephen-crawford Apr 3, 2023
ec78d12
Remove extra tests
stephen-crawford Apr 3, 2023
f27849d
Update imports
stephen-crawford Apr 3, 2023
fd6590c
Update imports
stephen-crawford Apr 3, 2023
8fe4cc2
Update imports
stephen-crawford Apr 3, 2023
247ceb6
Update contains
stephen-crawford Apr 4, 2023
4b711b0
fix service
stephen-crawford Apr 4, 2023
05f5611
Fix tests
stephen-crawford Apr 5, 2023
64ff012
remove prints
stephen-crawford Apr 5, 2023
1e7dc24
Clean service
stephen-crawford Apr 6, 2023
38299df
Clean service
stephen-crawford Apr 6, 2023
94780a5
Clean service
stephen-crawford Apr 6, 2023
ef69996
remove unused import
stephen-crawford Apr 6, 2023
406af1d
remove imports
stephen-crawford Apr 6, 2023
b07f0f8
fix user service and add tests
stephen-crawford Apr 7, 2023
205eac1
fix user service and add tests
stephen-crawford Apr 7, 2023
96a8bd0
Merge branch 'main' into ServiceAccounts
stephen-crawford Apr 7, 2023
fa052f0
resolve conflict
stephen-crawford Apr 7, 2023
c3c9c2f
Update imports
stephen-crawford Apr 7, 2023
7bf0eb2
Remove dangling test helper
stephen-crawford Apr 7, 2023
55ac310
fix tests
stephen-crawford Apr 10, 2023
0892086
remove messaging
stephen-crawford Apr 10, 2023
f550b73
reset auditlog file
stephen-crawford Apr 10, 2023
521b899
reset auditlog file
stephen-crawford Apr 10, 2023
b58e53d
reset auditlog file
stephen-crawford Apr 10, 2023
bb98d51
Merge branch 'opensearch-project:main' into ServiceAccounts
stephen-crawford Apr 12, 2023
9cb42ae
Cast message to string
stephen-crawford Apr 12, 2023
4a924ea
Swap tenancy action names
stephen-crawford Apr 12, 2023
1d230eb
Merge branch 'opensearch-project:main' into ServiceAccounts
stephen-crawford Apr 14, 2023
c078c51
reset tenancy action naem
stephen-crawford Apr 14, 2023
c17df56
Swap to node instead of parsing string and remove uneccessary additio…
stephen-crawford Apr 17, 2023
37ac417
remove unused imports
stephen-crawford Apr 17, 2023
3a106c5
Rollback changes and then remove extra lines
stephen-crawford Apr 20, 2023
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 @@ -175,6 +175,7 @@
import org.opensearch.security.transport.InterClusterRequestEvaluator;
import org.opensearch.security.transport.SecurityInterceptor;
import org.opensearch.security.user.User;
import org.opensearch.security.user.UserService;
import org.opensearch.tasks.Task;
import org.opensearch.threadpool.ThreadPool;
import org.opensearch.transport.RemoteClusterService;
Expand Down Expand Up @@ -203,6 +204,7 @@ public final class OpenSearchSecurityPlugin extends OpenSearchSecuritySSLPlugin
private volatile SecurityRestFilter securityRestHandler;
private volatile SecurityInterceptor si;
private volatile PrivilegesEvaluator evaluator;
private volatile UserService userService;
private volatile ThreadPool threadPool;
private volatile ConfigurationRepository cr;
private volatile AdminDNs adminDns;
Expand Down Expand Up @@ -486,6 +488,7 @@ public List<RestHandler> getRestHandlers(Settings settings, RestController restC
evaluator,
threadPool,
Objects.requireNonNull(auditLog), sks,
Objects.requireNonNull(userService),
sslCertReloadEnabled)
);
log.debug("Added {} rest handler(s)", handlers.size());
Expand Down Expand Up @@ -811,9 +814,11 @@ public Collection<Object> createComponents(Client localClient, ClusterService cl
sslExceptionHandler = new AuditLogSslExceptionHandler(auditLog);

adminDns = new AdminDNs(settings);

cr = ConfigurationRepository.create(settings, this.configPath, threadPool, localClient, clusterService, auditLog);

userService = new UserService(cs, cr, settings, localClient);

final XFFResolver xffResolver = new XFFResolver(threadPool);
backendRegistry = new BackendRegistry(settings, adminDns, xffResolver, auditLog, threadPool);

Expand Down Expand Up @@ -870,6 +875,7 @@ public Collection<Object> createComponents(Client localClient, ClusterService cl
components.add(evaluator);
components.add(si);
components.add(dcf);
components.add(userService);


return components;
Expand Down Expand Up @@ -1177,7 +1183,6 @@ public static class GuiceHolder implements LifecycleComponent {
private static RepositoriesService repositoriesService;
private static RemoteClusterService remoteClusterService;
private static IndicesService indicesService;

private static PitService pitService;

@Inject
Expand All @@ -1202,7 +1207,8 @@ public static IndicesService getIndicesService() {
}

public static PitService getPitService() { return pitService; }



@Override
public void close() {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Collectors;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
Expand All @@ -32,18 +31,18 @@
import org.opensearch.rest.RestController;
import org.opensearch.rest.RestRequest;
import org.opensearch.rest.RestRequest.Method;
import org.opensearch.security.DefaultObjectMapper;
import org.opensearch.security.auditlog.AuditLog;
import org.opensearch.security.configuration.AdminDNs;
import org.opensearch.security.configuration.ConfigurationRepository;
import org.opensearch.security.dlic.rest.validation.AbstractConfigurationValidator;
import org.opensearch.security.dlic.rest.validation.InternalUsersValidator;
import org.opensearch.security.privileges.PrivilegesEvaluator;
import org.opensearch.security.securityconf.Hashed;
import org.opensearch.security.securityconf.impl.CType;
import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration;
import org.opensearch.security.ssl.transport.PrincipalExtractor;
import org.opensearch.security.support.SecurityJsonNode;
import org.opensearch.security.user.UserService;
import org.opensearch.security.user.UserServiceException;
import org.opensearch.threadpool.ThreadPool;

import static org.opensearch.security.dlic.rest.support.Utils.addRoutesPrefix;
Expand All @@ -69,13 +68,16 @@ public class InternalUsersApiAction extends PatchableResourceApiAction {
new Route(Method.PATCH, "/internalusers/{name}")
));

UserService userService;

@Inject
public InternalUsersApiAction(final Settings settings, final Path configPath, final RestController controller,
final Client client, final AdminDNs adminDNs, final ConfigurationRepository cl,
final ClusterService cs, final PrincipalExtractor principalExtractor, final PrivilegesEvaluator evaluator,
ThreadPool threadPool, AuditLog auditLog) {
ThreadPool threadPool, UserService userService, AuditLog auditLog) {
super(settings, configPath, controller, client, adminDNs, cl, cs, principalExtractor, evaluator, threadPool,
auditLog);
this.userService = userService;
}

@Override
Expand All @@ -100,22 +102,7 @@ protected void handlePut(RestChannel channel, final RestRequest request, final C

final String username = request.param("name");

if (username == null || username.length() == 0) {
badRequestResponse(channel, "No " + getResourceName() + " specified.");
return;
}

final List<String> foundRestrictedContents = RESTRICTED_FROM_USERNAME.stream().filter(username::contains).collect(Collectors.toList());
if (!foundRestrictedContents.isEmpty()) {
final String restrictedContents = foundRestrictedContents.stream().map(s -> "'" + s + "'").collect(Collectors.joining(","));
badRequestResponse(channel, "Username has restricted characters " + restrictedContents + " that are not permitted.");
return;
}

// TODO it might be sensible to consolidate this with the overridden method in
// order to minimize duplicated logic

final SecurityDynamicConfiguration<?> internalUsersConfiguration = load(getConfigName(), false);
SecurityDynamicConfiguration<?> internalUsersConfiguration = load(getConfigName(), false);

if (!isWriteable(channel, internalUsersConfiguration, username)) {
return;
Expand All @@ -128,50 +115,35 @@ protected void handlePut(RestChannel channel, final RestRequest request, final C
final List<String> securityRoles = securityJsonNode.get("opendistro_security_roles").asList();
if (securityRoles != null) {
for (final String role: securityRoles) {
if (!isValidRolesMapping(channel, role)) return;
if (!isValidRolesMapping(channel, role)) {
return;
}
}
}

// if password is set, it takes precedence over hash
final String plainTextPassword = securityJsonNode.get("password").asString();
final String origHash = securityJsonNode.get("hash").asString();
if (plainTextPassword != null && plainTextPassword.length() > 0) {
contentAsNode.remove("password");
contentAsNode.put("hash", hash(plainTextPassword.toCharArray()));
} else if (origHash != null && origHash.length() > 0) {
contentAsNode.remove("password");
} else if (plainTextPassword != null && plainTextPassword.isEmpty() && origHash == null) {
contentAsNode.remove("password");
}

final boolean userExisted = internalUsersConfiguration.exists(username);

// when updating an existing user password hash can be blank, which means no
// changes

// sanity checks, hash is mandatory for newly created users
if (!userExisted && securityJsonNode.get("hash").asString() == null) {
badRequestResponse(channel, "Please specify either 'hash' or 'password' when creating a new internal user.");
try {
if (request.hasParam("owner")) {
stephen-crawford marked this conversation as resolved.
Show resolved Hide resolved
((ObjectNode) content).put("owner", request.param("owner"));
}
if (request.hasParam("isEnabled")) {
stephen-crawford marked this conversation as resolved.
Show resolved Hide resolved
((ObjectNode) content).put("isEnabled", request.param("isEnabled"));
stephen-crawford marked this conversation as resolved.
Show resolved Hide resolved
}
((ObjectNode) content).put("name", username);
internalUsersConfiguration = userService.createOrUpdateAccount((ObjectNode) content);
}
catch (UserServiceException ex) {
badRequestResponse(channel, ex.getMessage());
return;
}

// for existing users, hash is optional
if (userExisted && securityJsonNode.get("hash").asString() == null) {
// sanity check, this should usually not happen
final String hash = ((Hashed) internalUsersConfiguration.getCEntry(username)).getHash();
if (hash == null || hash.length() == 0) {
internalErrorResponse(channel,
"Existing user " + username + " has no password, and no new password or hash was specified.");
return;
}
contentAsNode.put("hash", hash);
catch (IOException ex) {
throw new IOException(ex);
}

internalUsersConfiguration.remove(username);

// checks complete, create or update the user
internalUsersConfiguration.putCObject(username, DefaultObjectMapper.readTree(contentAsNode, internalUsersConfiguration.getImplementingClass()));

saveAndUpdateConfigs(this.securityIndexName,client, CType.INTERNALUSERS, internalUsersConfiguration, new OnSucessActionListener<IndexResponse>(channel) {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.opensearch.security.privileges.PrivilegesEvaluator;
import org.opensearch.security.ssl.SecurityKeyStore;
import org.opensearch.security.ssl.transport.PrincipalExtractor;
import org.opensearch.security.user.UserService;
import org.opensearch.threadpool.ThreadPool;

public class SecurityRestApiActions {
Expand All @@ -44,9 +45,10 @@ public static Collection<RestHandler> getHandler(final Settings settings,
final ThreadPool threadPool,
final AuditLog auditLog,
final SecurityKeyStore securityKeyStore,
final UserService userService,
final boolean certificatesReloadEnabled) {
final List<RestHandler> handlers = new ArrayList<RestHandler>(16);
handlers.add(new InternalUsersApiAction(settings, configPath, controller, client, adminDns, cr, cs, principalExtractor, evaluator, threadPool, auditLog));
handlers.add(new InternalUsersApiAction(settings, configPath, controller, client, adminDns, cr, cs, principalExtractor, evaluator, threadPool, userService, auditLog));
handlers.add(new RolesMappingApiAction(settings, configPath, controller, client, adminDns, cr, cs, principalExtractor, evaluator, threadPool, auditLog));
handlers.add(new RolesApiAction(settings, configPath, controller, client, adminDns, cr, cs, principalExtractor, evaluator, threadPool, auditLog));
handlers.add(new ActionGroupsApiAction(settings, configPath, controller, client, adminDns, cr, cs, principalExtractor, evaluator, threadPool, auditLog));
Expand Down
Loading