Skip to content
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
5 changes: 5 additions & 0 deletions docs/changelog/92168.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 92168
summary: Make adding auth info to REST responses more robust
area: Authorization
type: bug
issues: []
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

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

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.Version;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.util.concurrent.ThreadContext;
Expand All @@ -23,6 +25,8 @@
*/
public class AuthenticationContextSerializer {

private static final Logger logger = LogManager.getLogger(AuthenticationContextSerializer.class);

private final String contextKey;

public AuthenticationContextSerializer() {
Expand Down Expand Up @@ -57,11 +61,16 @@ Authentication deserializeHeaderAndPutInContext(String headerValue, ThreadContex
}

public static Authentication decode(String header) throws IOException {
byte[] bytes = Base64.getDecoder().decode(header);
StreamInput input = StreamInput.wrap(bytes);
Version version = Version.readVersion(input);
input.setVersion(version);
return new Authentication(input);
try {
byte[] bytes = Base64.getDecoder().decode(header);
StreamInput input = StreamInput.wrap(bytes);
Version version = Version.readVersion(input);
input.setVersion(version);
return new Authentication(input);
} catch (IOException | RuntimeException e) {
logger.warn("Failed to decode authentication [" + header + "]", e);
throw e;
}
}

public Authentication getAuthentication(ThreadContext context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,16 +94,22 @@ public static void addAuthorizationInfo(final XContentBuilder builder, final Map
if (authKey == null) {
return;
}
Subject authenticationSubject;
try {
authenticationSubject = AuthenticationContextSerializer.decode(authKey).getEffectiveSubject();
} catch (Exception e) {
// The exception will have been logged by AuthenticationContextSerializer.decode() so don't log it again here.
return;
}
builder.startObject("authorization");
Subject authenticationSubject = AuthenticationContextSerializer.decode(authKey).getEffectiveSubject();
switch (authenticationSubject.getType()) {
case USER -> builder.array(User.Fields.ROLES.getPreferredName(), authenticationSubject.getUser().roles());
case API_KEY -> {
builder.startObject("api_key");
Map<String, Object> metadata = authenticationSubject.getMetadata();
builder.field("id", metadata.get(AuthenticationField.API_KEY_ID_KEY));
Object name = metadata.get(AuthenticationField.API_KEY_NAME_KEY);
if (name != null) {
if (name instanceof String) {
builder.field("name", name);
}
builder.endObject();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ public void testAddAuthorizationInfoWithServiceAccount() throws IOException {
assertThat(json, equalTo("{\"authorization\":{\"service_account\":\"" + account + "\"}}"));
}

public void testAddAuthorizationInfoWithCorruptData() throws IOException {
String json = generateJson(Map.of(AuthenticationField.AUTHENTICATION_KEY, "corrupt"));
assertThat(json, equalTo("{}"));
}

private String generateJson(Map<String, String> headers) throws IOException {
try (XContentBuilder builder = JsonXContent.contentBuilder()) {
builder.startObject();
Expand Down