Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
jakelandis committed Mar 20, 2024
1 parent 2988799 commit 76ed6ef
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import org.junit.After;
import org.junit.Before;

import java.util.Set;

import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
Expand Down Expand Up @@ -114,7 +116,7 @@ public void testApply_ActionDisallowedInUpgradeModeWithResetModeExemption() {

public void testOrder_UpgradeFilterIsExecutedAfterSecurityFilter() {
MlUpgradeModeActionFilter upgradeModeFilter = new MlUpgradeModeActionFilter(clusterService);
SecurityActionFilter securityFilter = new SecurityActionFilter(null, null, null, null, mock(ThreadPool.class), null, null);
SecurityActionFilter securityFilter = new SecurityActionFilter(null, null, null, null, mock(ThreadPool.class), null, null, Set::of);

ActionFilter[] actionFiltersInOrderOfExecution = new ActionFilters(Sets.newHashSet(upgradeModeFilter, securityFilter)).filters();
assertThat(actionFiltersInOrderOfExecution, is(arrayContaining(securityFilter, upgradeModeFilter)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@
import org.elasticsearch.xpack.security.authc.service.FileServiceAccountTokenStore;
import org.elasticsearch.xpack.security.authc.service.IndexServiceAccountTokenStore;
import org.elasticsearch.xpack.security.authc.service.ServiceAccountService;
import org.elasticsearch.xpack.security.authc.support.SecondaryAuthActions;
import org.elasticsearch.xpack.security.authc.support.SecondaryAuthenticator;
import org.elasticsearch.xpack.security.authc.support.mapper.NativeRoleMappingStore;
import org.elasticsearch.xpack.security.authz.AuthorizationDenialMessages;
Expand Down Expand Up @@ -583,6 +584,7 @@ public class Security extends Plugin
private final SetOnce<Client> client = new SetOnce<>();
private final SetOnce<List<ReloadableSecurityComponent>> reloadableComponents = new SetOnce<>();
private final SetOnce<AuthorizationDenialMessages> authorizationDenialMessages = new SetOnce<>();
private final SetOnce<SecondaryAuthActions> secondaryAuthActions = new SetOnce<>();

public Security(Settings settings) {
this(settings, Collections.emptyList());
Expand Down Expand Up @@ -1071,7 +1073,8 @@ Collection<Object> createComponents(
getLicenseState(),
threadPool,
securityContext.get(),
destructiveOperations
destructiveOperations,
secondaryAuthActions.get() == null ? Set::of : secondaryAuthActions.get()
)
);

Expand Down Expand Up @@ -2105,6 +2108,7 @@ public void loadExtensions(ExtensionLoader loader) {
loadSingletonExtensionAndSetOnce(loader, createApiKeyRequestBuilderFactory, CreateApiKeyRequestBuilderFactory.class);
loadSingletonExtensionAndSetOnce(loader, hasPrivilegesRequestBuilderFactory, HasPrivilegesRequestBuilderFactory.class);
loadSingletonExtensionAndSetOnce(loader, authorizationDenialMessages, AuthorizationDenialMessages.class);
loadSingletonExtensionAndSetOnce(loader, secondaryAuthActions, SecondaryAuthActions.class); // TODO: move this xpack core
}

private <T> void loadSingletonExtensionAndSetOnce(ExtensionLoader loader, SetOnce<T> setOnce, Class<T> clazz) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.core.XPackField;
import org.elasticsearch.xpack.core.security.SecurityContext;
import org.elasticsearch.xpack.core.security.authc.support.SecondaryAuthentication;
import org.elasticsearch.xpack.core.security.authz.privilege.HealthAndStatsPrivilege;
import org.elasticsearch.xpack.core.security.user.InternalUsers;
import org.elasticsearch.xpack.security.action.SecurityActionMapper;
import org.elasticsearch.xpack.security.audit.AuditTrailService;
import org.elasticsearch.xpack.security.audit.AuditUtil;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.authc.support.SecondaryAuthActions;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import org.elasticsearch.xpack.security.authz.AuthorizationUtils;

Expand All @@ -51,6 +53,7 @@ public class SecurityActionFilter implements ActionFilter {
private final ThreadContext threadContext;
private final SecurityContext securityContext;
private final DestructiveOperations destructiveOperations;
private final SecondaryAuthActions secondaryAuthActions;

public SecurityActionFilter(
AuthenticationService authcService,
Expand All @@ -59,7 +62,8 @@ public SecurityActionFilter(
XPackLicenseState licenseState,
ThreadPool threadPool,
SecurityContext securityContext,
DestructiveOperations destructiveOperations
DestructiveOperations destructiveOperations,
SecondaryAuthActions secondaryAuthActions
) {
this.authcService = authcService;
this.authzService = authzService;
Expand All @@ -68,6 +72,7 @@ public SecurityActionFilter(
this.threadContext = threadPool.getThreadContext();
this.securityContext = securityContext;
this.destructiveOperations = destructiveOperations;
this.secondaryAuthActions = secondaryAuthActions;
}

@Override
Expand Down Expand Up @@ -109,6 +114,16 @@ operations are blocked on license expiration. All data operations (read and writ
TransportVersion.current(), // current version since this is on the same node
(original) -> { applyInternal(task, chain, action, request, contextPreservingListener); }
);
} else if (secondaryAuthActions.get().contains(action)) {
SecondaryAuthentication secondaryAuth = securityContext.getSecondaryAuthentication();
if (secondaryAuth == null) {
throw new IllegalArgumentException("es-secondary-authorization header must be used to call action [" + action + "]");
} else {
secondaryAuth.execute(ignore -> {
applyInternal(task, chain, action, request, contextPreservingListener);
return null;
});
}
} else {
try (ThreadContext.StoredContext ignore = threadContext.newStoredContextPreservingResponseHeaders()) {
applyInternal(task, chain, action, request, contextPreservingListener);
Expand Down Expand Up @@ -154,6 +169,7 @@ it to the action without an associated user (not via REST or transport - this is
here if a request is not associated with any other user.
*/
final String securityAction = SecurityActionMapper.action(action, request);

authcService.authenticate(securityAction, request, InternalUsers.SYSTEM_USER, listener.delegateFailureAndWrap((delegate, authc) -> {
if (authc != null) {
final String requestId = AuditUtil.extractRequestId(threadContext);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

package org.elasticsearch.xpack.security.authc.support;

import java.util.Set;

/**
* Actions that are only available when a secondary authenticator is present. The user represented by the secondary authenticator will
* be used as the user for these actions. Secondary authorization requires both the primary and secondary authentication passes.
* Any actions returned here will ensure that the RBAC authorization represents the secondary user.
* If these actions are called without a secondary authenticated user, an exception will be thrown.
* {@see SecondaryAuthenticator}
*/
@FunctionalInterface
public interface SecondaryAuthActions {
Set<String> get();
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import org.junit.Before;

import java.util.Collections;
import java.util.Set;

import static org.elasticsearch.test.ActionListenerUtils.anyActionListener;
import static org.elasticsearch.xpack.core.security.authz.AuthorizationServiceField.INDICES_PERMISSIONS_KEY;
Expand Down Expand Up @@ -114,7 +115,8 @@ public void init() throws Exception {
licenseState,
threadPool,
securityContext,
destructiveOperations
destructiveOperations,
Set::of
);
}

Expand Down

0 comments on commit 76ed6ef

Please sign in to comment.