Skip to content

Commit 2cf2311

Browse files
authored
[Backport 7.9][API keys] Add full_name and email to API key doc and use them to populate authing User (#61354) (#61404)
The API key document currently doesn't include the user's full_name or email attributes, and as a result, when those attributes return `null` when hitting `GET`ing `/_security/_authenticate`, and in the SAML response from the [IdP Plugin](#54046). This changeset adds those fields to the document and extracts them to fill in the User when authenticating. They're effectively going to be a snapshot of the User from when the key was created, but this is in line with roles and metadata as well. Signed-off-by: lloydmeta <[email protected]>
1 parent a940318 commit 2cf2311

File tree

4 files changed

+50
-5
lines changed

4 files changed

+50
-5
lines changed

x-pack/plugin/core/src/main/resources/security-index-template-7.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,13 @@
188188
"principal" : {
189189
"type": "keyword"
190190
},
191+
"full_name" : {
192+
"type" : "text"
193+
},
194+
"email" : {
195+
"type" : "text",
196+
"analyzer" : "email"
197+
},
191198
"metadata" : {
192199
"type" : "object",
193200
"dynamic" : false

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,8 @@ XContentBuilder newDocument(SecureString apiKey, String name, Authentication aut
302302
.field("version", version.id)
303303
.startObject("creator")
304304
.field("principal", authentication.getUser().principal())
305+
.field("full_name", authentication.getUser().fullName())
306+
.field("email", authentication.getUser().email())
305307
.field("metadata", authentication.getUser().metadata())
306308
.field("realm", authentication.getSourceRealm().getName())
307309
.field("realm_type", authentication.getSourceRealm().getType())
@@ -597,8 +599,10 @@ void validateApiKeyExpiration(ApiKeyDoc apiKeyDoc, ApiKeyCredentials credentials
597599
ActionListener<AuthenticationResult> listener) {
598600
if (apiKeyDoc.expirationTime == -1 || Instant.ofEpochMilli(apiKeyDoc.expirationTime).isAfter(clock.instant())) {
599601
final String principal = Objects.requireNonNull((String) apiKeyDoc.creator.get("principal"));
602+
final String fullName = (String) apiKeyDoc.creator.get("full_name");
603+
final String email = (String) apiKeyDoc.creator.get("email");
600604
Map<String, Object> metadata = (Map<String, Object>) apiKeyDoc.creator.get("metadata");
601-
final User apiKeyUser = new User(principal, Strings.EMPTY_ARRAY, null, null, metadata, true);
605+
final User apiKeyUser = new User(principal, Strings.EMPTY_ARRAY, fullName, email, metadata, true);
602606
final Map<String, Object> authResultMetadata = new HashMap<>();
603607
authResultMetadata.put(API_KEY_CREATOR_REALM_NAME, apiKeyDoc.creator.get("realm"));
604608
authResultMetadata.put(API_KEY_CREATOR_REALM_TYPE, apiKeyDoc.creator.get("realm_type"));

x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -196,16 +196,35 @@ public void testAuthenticateWithApiKey() throws Exception {
196196

197197
final User user;
198198
if (randomBoolean()) {
199-
user = new User("hulk", new String[] { "superuser" }, new User("authenticated_user", new String[] { "other" }));
199+
user = new User(
200+
new User(
201+
"hulk",
202+
new String[]{"superuser"},
203+
"Bruce Banner",
204+
205+
org.elasticsearch.common.collect.Map.of(),
206+
true
207+
),
208+
new User("authenticated_user", new String[]{"other"})
209+
);
200210
} else {
201-
user = new User("hulk", new String[] { "superuser" });
211+
user = new User(
212+
"hulk",
213+
new String[]{"superuser"},
214+
"Bruce Banner",
215+
216+
org.elasticsearch.common.collect.Map.of(),
217+
true
218+
);
202219
}
203220
mockKeyDocument(service, id, key, user);
204221

205222
final AuthenticationResult auth = tryAuthenticate(service, id, key);
206223
assertThat(auth.getStatus(), is(AuthenticationResult.Status.SUCCESS));
207224
assertThat(auth.getUser(), notNullValue());
208225
assertThat(auth.getUser().principal(), is("hulk"));
226+
assertThat(auth.getUser().fullName(), is("Bruce Banner"));
227+
assertThat(auth.getUser().email(), is("[email protected]"));
209228
assertThat(auth.getMetadata().get(ApiKeyService.API_KEY_CREATOR_REALM_NAME), is("realm1"));
210229
assertThat(auth.getMetadata().get(ApiKeyService.API_KEY_CREATOR_REALM_TYPE), is("native"));
211230
assertThat(auth.getMetadata().get(ApiKeyService.API_KEY_ID_KEY), is(id));
@@ -377,6 +396,8 @@ public void testValidateApiKey() throws Exception {
377396
assertNotNull(result);
378397
assertTrue(result.isAuthenticated());
379398
assertThat(result.getUser().principal(), is("test_user"));
399+
assertThat(result.getUser().fullName(), is("test user"));
400+
assertThat(result.getUser().email(), is("[email protected]"));
380401
assertThat(result.getUser().roles(), is(emptyArray()));
381402
assertThat(result.getUser().metadata(), is(Collections.emptyMap()));
382403
assertThat(result.getMetadata().get(API_KEY_ROLE_DESCRIPTORS_KEY), equalTo(apiKeyDoc.roleDescriptorsBytes));
@@ -391,6 +412,8 @@ public void testValidateApiKey() throws Exception {
391412
assertNotNull(result);
392413
assertTrue(result.isAuthenticated());
393414
assertThat(result.getUser().principal(), is("test_user"));
415+
assertThat(result.getUser().fullName(), is("test user"));
416+
assertThat(result.getUser().email(), is("[email protected]"));
394417
assertThat(result.getUser().roles(), is(emptyArray()));
395418
assertThat(result.getUser().metadata(), is(Collections.emptyMap()));
396419
assertThat(result.getMetadata().get(API_KEY_ROLE_DESCRIPTORS_KEY), equalTo(apiKeyDoc.roleDescriptorsBytes));
@@ -923,6 +946,8 @@ private Map<String, Object> buildApiKeySourceDoc(char[] hash) {
923946
sourceMap.put("limited_by_role_descriptors", Collections.singletonMap("limited role", Collections.singletonMap("cluster", "all")));
924947
Map<String, Object> creatorMap = new HashMap<>();
925948
creatorMap.put("principal", "test_user");
949+
creatorMap.put("full_name", "test user");
950+
creatorMap.put("email", "[email protected]");
926951
creatorMap.put("metadata", Collections.emptyMap());
927952
sourceMap.put("creator", creatorMap);
928953
sourceMap.put("api_key_invalidated", false);
@@ -954,8 +979,13 @@ private ApiKeyDoc buildApiKeyDoc(char[] hash, long expirationTime, boolean inval
954979
new BytesArray("{\"a role\": {\"cluster\": [\"all\"]}}"),
955980
new BytesArray("{\"limited role\": {\"cluster\": [\"all\"]}}"),
956981
org.elasticsearch.common.collect.Map.of(
957-
"principal", "test_user", "realm", "realm1", "realm_type", "realm_type1", "metadata",
958-
org.elasticsearch.common.collect.Map.of())
982+
"principal", "test_user",
983+
"full_name", "test user",
984+
"email", "[email protected]",
985+
"realm", "realm1",
986+
"realm_type", "realm_type1",
987+
"metadata", org.elasticsearch.common.collect.Map.of()
988+
)
959989
);
960990
}
961991
}

x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,6 +1421,8 @@ public void testApiKeyAuth() {
14211421
source.put("version", 0);
14221422
Map<String, Object> creatorMap = new HashMap<>();
14231423
creatorMap.put("principal", "johndoe");
1424+
creatorMap.put("full_name", "john doe");
1425+
creatorMap.put("email", "[email protected]");
14241426
creatorMap.put("metadata", Collections.emptyMap());
14251427
creatorMap.put("realm", "auth realm");
14261428
source.put("creator", creatorMap);
@@ -1439,6 +1441,8 @@ public void testApiKeyAuth() {
14391441
threadContext.putHeader("Authorization", headerValue);
14401442
final Authentication authentication = authenticateBlocking("_action", transportRequest, null);
14411443
assertThat(authentication.getUser().principal(), is("johndoe"));
1444+
assertThat(authentication.getUser().fullName(), is("john doe"));
1445+
assertThat(authentication.getUser().email(), is("[email protected]"));
14421446
assertThat(authentication.getAuthenticationType(), is(AuthenticationType.API_KEY));
14431447
}
14441448
}

0 commit comments

Comments
 (0)