Skip to content

Commit 9f55b01

Browse files
committed
Show Original User in Slow Logs for RCS 2.0
1 parent 379a539 commit 9f55b01

File tree

2 files changed

+433
-20
lines changed

2 files changed

+433
-20
lines changed

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java

Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2403,34 +2403,72 @@ private void reloadRemoteClusterCredentials(Settings settingsWithKeystore) {
24032403
public Map<String, String> getAuthContextForSlowLog() {
24042404
if (this.securityContext.get() != null && this.securityContext.get().getAuthentication() != null) {
24052405
Authentication authentication = this.securityContext.get().getAuthentication();
2406-
Subject authenticatingSubject = authentication.getAuthenticatingSubject();
2407-
Subject effetctiveSubject = authentication.getEffectiveSubject();
24082406
Map<String, String> authContext = new HashMap<>();
2409-
if (authenticatingSubject.getUser() != null) {
2410-
authContext.put("user.name", authenticatingSubject.getUser().principal());
2411-
authContext.put("user.realm", authenticatingSubject.getRealm().getName());
2412-
if (authenticatingSubject.getUser().fullName() != null) {
2413-
authContext.put("user.full_name", authenticatingSubject.getUser().fullName());
2414-
}
2415-
}
2416-
// Only include effective user if different from authenticating user (run-as)
2417-
if (effetctiveSubject.getUser() != null && effetctiveSubject.equals(authenticatingSubject) == false) {
2418-
authContext.put("user.effective.name", effetctiveSubject.getUser().principal());
2419-
authContext.put("user.effective.realm", effetctiveSubject.getRealm().getName());
2420-
if (effetctiveSubject.getUser().fullName() != null) {
2421-
authContext.put("user.effective.full_name", effetctiveSubject.getUser().fullName());
2422-
}
2407+
2408+
// Handle Cross-Cluster Access (RCS 2.0) scenario
2409+
if (authentication.isCrossClusterAccess()) {
2410+
Authentication originalAuthentication = Authentication.getAuthenticationFromCrossClusterAccessMetadata(authentication);
2411+
// Call the helper method for the originalAuthentication (from querying cluster)
2412+
populateAuthContextMap(originalAuthentication, authContext);
24232413
}
2424-
authContext.put("auth.type", authentication.getAuthenticationType().name());
2425-
if (authentication.isApiKey()) {
2426-
authContext.put("apikey.id", authenticatingSubject.getMetadata().get(AuthenticationField.API_KEY_ID_KEY).toString());
2427-
authContext.put("apikey.name", authenticatingSubject.getMetadata().get(AuthenticationField.API_KEY_NAME_KEY).toString());
2414+
// Logic for obtaining non-cross-cluster access authentication information
2415+
else {
2416+
// Call the helper method for the authentication itself
2417+
populateAuthContextMap(authentication, authContext);
24282418
}
24292419
return authContext;
24302420
}
24312421
return Map.of();
24322422
}
24332423

2424+
/**
2425+
* Helper method to populate authentication context fields for slow logs.
2426+
* This logic is common for both direct authentications and the nested
2427+
* original authentication in cross-cluster access scenarios.
2428+
*
2429+
* @param auth The Authentication object to extract details from.
2430+
* @param authContext The map to populate with authentication details.
2431+
*/
2432+
private void populateAuthContextMap(Authentication auth, Map<String, String> authContext) {
2433+
Subject authenticatingSubject = auth.getAuthenticatingSubject();
2434+
Subject effectiveSubject = auth.getEffectiveSubject();
2435+
2436+
// The primary user.name and user.realm fields should reflect the AUTHENTICATING user
2437+
if (authenticatingSubject.getUser() != null) {
2438+
authContext.put("user.name", authenticatingSubject.getUser().principal());
2439+
authContext.put("user.realm", authenticatingSubject.getRealm().getName());
2440+
if (authenticatingSubject.getUser().fullName() != null) {
2441+
authContext.put("user.full_name", authenticatingSubject.getUser().fullName());
2442+
}
2443+
}
2444+
2445+
// Only include effective user if different from authenticating user (run-as)
2446+
if (auth.isRunAs()) { // Use auth.isRunAs() for consistency
2447+
if (effectiveSubject.getUser() != null) {
2448+
authContext.put("user.effective.name", effectiveSubject.getUser().principal());
2449+
authContext.put("user.effective.realm", effectiveSubject.getRealm().getName());
2450+
if (effectiveSubject.getUser().fullName() != null) {
2451+
authContext.put("user.effective.full_name", effectiveSubject.getUser().fullName());
2452+
}
2453+
}
2454+
}
2455+
2456+
// Auth type
2457+
authContext.put("auth.type", auth.getAuthenticationType().name());
2458+
2459+
// Add API key details if this authentication was an API key itself
2460+
if (auth.isApiKey()) {
2461+
// These metadata fields are expected to be on the authenticating subject of the API key
2462+
// Use Objects.toString() for safety against null metadata values if not strictly guaranteed
2463+
authContext.put("apikey.id", Objects.toString(authenticatingSubject.getMetadata().get(AuthenticationField.API_KEY_ID_KEY)));
2464+
2465+
Object apiKeyName = authenticatingSubject.getMetadata().get(AuthenticationField.API_KEY_NAME_KEY);
2466+
if (apiKeyName != null) { // Name can be null for API keys, so check explicitly
2467+
authContext.put("apikey.name", apiKeyName.toString());
2468+
}
2469+
}
2470+
}
2471+
24342472
static final class ValidateLicenseForFIPS implements BiConsumer<DiscoveryNode, ClusterState> {
24352473
private final boolean inFipsMode;
24362474
private final LicenseService licenseService;

0 commit comments

Comments
 (0)