Skip to content

Commit 53adb09

Browse files
Authentication under domains (#82639)
This makes the ubiquitous Authentication object contain the domain information that will later be used for access control decisions related to ownership. The domain information is a Set of RealmIdentifiers of the authentication realms configured under the same domain name.
1 parent fe29908 commit 53adb09

File tree

41 files changed

+1167
-602
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1167
-602
lines changed

docs/changelog/82639.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 82639
2+
summary: Authentication under domains
3+
area: Authentication
4+
type: enhancement
5+
issues: []

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

Lines changed: 22 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -10,41 +10,29 @@
1010
import org.apache.logging.log4j.Logger;
1111
import org.elasticsearch.ElasticsearchSecurityException;
1212
import org.elasticsearch.Version;
13-
import org.elasticsearch.common.bytes.BytesReference;
1413
import org.elasticsearch.common.settings.Settings;
1514
import org.elasticsearch.common.util.concurrent.ThreadContext;
1615
import org.elasticsearch.common.util.concurrent.ThreadContext.StoredContext;
17-
import org.elasticsearch.common.xcontent.XContentHelper;
1816
import org.elasticsearch.core.Nullable;
1917
import org.elasticsearch.node.Node;
20-
import org.elasticsearch.xcontent.XContentBuilder;
21-
import org.elasticsearch.xcontent.XContentType;
2218
import org.elasticsearch.xpack.core.security.authc.Authentication;
23-
import org.elasticsearch.xpack.core.security.authc.Authentication.AuthenticationType;
24-
import org.elasticsearch.xpack.core.security.authc.AuthenticationField;
2519
import org.elasticsearch.xpack.core.security.authc.support.AuthenticationContextSerializer;
2620
import org.elasticsearch.xpack.core.security.authc.support.SecondaryAuthentication;
21+
import org.elasticsearch.xpack.core.security.user.SystemUser;
2722
import org.elasticsearch.xpack.core.security.user.User;
2823

2924
import java.io.IOException;
3025
import java.io.UncheckedIOException;
31-
import java.util.Collections;
32-
import java.util.HashMap;
3326
import java.util.Map;
34-
import java.util.Objects;
3527
import java.util.function.Consumer;
3628
import java.util.function.Function;
3729

38-
import static org.elasticsearch.xpack.core.security.authc.Authentication.VERSION_API_KEY_ROLES_AS_BYTES;
39-
import static org.elasticsearch.xpack.core.security.authc.AuthenticationField.ATTACH_REALM_NAME;
40-
import static org.elasticsearch.xpack.core.security.authc.AuthenticationField.ATTACH_REALM_TYPE;
41-
4230
/**
4331
* A lightweight utility that can find the current user and authentication information for the local thread.
4432
*/
4533
public class SecurityContext {
4634

47-
private final Logger logger = LogManager.getLogger(SecurityContext.class);
35+
private static final Logger logger = LogManager.getLogger(SecurityContext.class);
4836

4937
private final ThreadContext threadContext;
5038
private final AuthenticationContextSerializer authenticationSerializer;
@@ -107,41 +95,32 @@ public ThreadContext getThreadContext() {
10795
* Sets the user forcefully to the provided user. There must not be an existing user in the ThreadContext otherwise an exception
10896
* will be thrown. This method is package private for testing.
10997
*/
110-
public void setUser(User user, Version version) {
111-
Objects.requireNonNull(user);
112-
final Authentication.RealmRef authenticatedBy = new Authentication.RealmRef(ATTACH_REALM_NAME, ATTACH_REALM_TYPE, nodeName);
113-
final Authentication.RealmRef lookedUpBy;
114-
if (user.isRunAs()) {
115-
lookedUpBy = authenticatedBy;
116-
} else {
117-
lookedUpBy = null;
118-
}
119-
setAuthentication(
120-
new Authentication(user, authenticatedBy, lookedUpBy, version, AuthenticationType.INTERNAL, Collections.emptyMap())
121-
);
122-
}
123-
124-
/** Writes the authentication to the thread context */
125-
private void setAuthentication(Authentication authentication) {
126-
try {
127-
authentication.writeToContext(threadContext);
128-
} catch (IOException e) {
129-
throw new AssertionError("how can we have a IOException with a user we set", e);
130-
}
98+
public void setInternalUser(User internalUser, Version version) {
99+
assert User.isInternal(internalUser);
100+
setAuthentication(Authentication.newInternalAuthentication(internalUser, version, nodeName));
131101
}
132102

133103
/**
134104
* Runs the consumer in a new context as the provided user. The original context is provided to the consumer. When this method
135105
* returns, the original context is restored.
136106
*/
137-
public void executeAsUser(User user, Consumer<StoredContext> consumer, Version version) {
107+
public void executeAsInternalUser(User internalUser, Version version, Consumer<StoredContext> consumer) {
108+
assert User.isInternal(internalUser);
138109
final StoredContext original = threadContext.newStoredContext(true);
139110
try (ThreadContext.StoredContext ignore = threadContext.stashContext()) {
140-
setUser(user, version);
111+
setInternalUser(internalUser, version);
141112
consumer.accept(original);
142113
}
143114
}
144115

116+
public void executeAsSystemUser(Consumer<StoredContext> consumer) {
117+
executeAsSystemUser(Version.CURRENT, consumer);
118+
}
119+
120+
public void executeAsSystemUser(Version version, Consumer<StoredContext> consumer) {
121+
executeAsInternalUser(SystemUser.INSTANCE, version, consumer);
122+
}
123+
145124
/**
146125
* Runs the consumer in a new context as the provided user. The original context is provided to the consumer. When this method
147126
* returns, the original context is restored.
@@ -164,16 +143,7 @@ public void executeAfterRewritingAuthentication(Consumer<StoredContext> consumer
164143
final StoredContext original = threadContext.newStoredContext(true);
165144
final Authentication authentication = getAuthentication();
166145
try (ThreadContext.StoredContext ignore = threadContext.stashContext()) {
167-
setAuthentication(
168-
new Authentication(
169-
authentication.getUser(),
170-
authentication.getAuthenticatedBy(),
171-
authentication.getLookedUpBy(),
172-
version,
173-
authentication.getAuthenticationType(),
174-
rewriteMetadataForApiKeyRoleDescriptors(version, authentication)
175-
)
176-
);
146+
setAuthentication(authentication.maybeRewriteForOlderVersion(version));
177147
existingRequestHeaders.forEach((k, v) -> {
178148
if (threadContext.getHeader(k) == null) {
179149
threadContext.putHeader(k, v);
@@ -183,54 +153,12 @@ public void executeAfterRewritingAuthentication(Consumer<StoredContext> consumer
183153
}
184154
}
185155

186-
@SuppressWarnings("unchecked")
187-
private Map<String, Object> rewriteMetadataForApiKeyRoleDescriptors(Version streamVersion, Authentication authentication) {
188-
Map<String, Object> metadata = authentication.getMetadata();
189-
// If authentication type is API key, regardless whether it has run-as, the metadata must contain API key role descriptors
190-
if (authentication.isAuthenticatedWithApiKey()) {
191-
if (authentication.getVersion().onOrAfter(VERSION_API_KEY_ROLES_AS_BYTES)
192-
&& streamVersion.before(VERSION_API_KEY_ROLES_AS_BYTES)) {
193-
metadata = new HashMap<>(metadata);
194-
metadata.put(
195-
AuthenticationField.API_KEY_ROLE_DESCRIPTORS_KEY,
196-
convertRoleDescriptorsBytesToMap((BytesReference) metadata.get(AuthenticationField.API_KEY_ROLE_DESCRIPTORS_KEY))
197-
);
198-
metadata.put(
199-
AuthenticationField.API_KEY_LIMITED_ROLE_DESCRIPTORS_KEY,
200-
convertRoleDescriptorsBytesToMap(
201-
(BytesReference) metadata.get(AuthenticationField.API_KEY_LIMITED_ROLE_DESCRIPTORS_KEY)
202-
)
203-
);
204-
} else if (authentication.getVersion().before(VERSION_API_KEY_ROLES_AS_BYTES)
205-
&& streamVersion.onOrAfter(VERSION_API_KEY_ROLES_AS_BYTES)) {
206-
metadata = new HashMap<>(metadata);
207-
metadata.put(
208-
AuthenticationField.API_KEY_ROLE_DESCRIPTORS_KEY,
209-
convertRoleDescriptorsMapToBytes(
210-
(Map<String, Object>) metadata.get(AuthenticationField.API_KEY_ROLE_DESCRIPTORS_KEY)
211-
)
212-
);
213-
metadata.put(
214-
AuthenticationField.API_KEY_LIMITED_ROLE_DESCRIPTORS_KEY,
215-
convertRoleDescriptorsMapToBytes(
216-
(Map<String, Object>) metadata.get(AuthenticationField.API_KEY_LIMITED_ROLE_DESCRIPTORS_KEY)
217-
)
218-
);
219-
}
220-
}
221-
return metadata;
222-
}
223-
224-
private Map<String, Object> convertRoleDescriptorsBytesToMap(BytesReference roleDescriptorsBytes) {
225-
return XContentHelper.convertToMap(roleDescriptorsBytes, false, XContentType.JSON).v2();
226-
}
227-
228-
private BytesReference convertRoleDescriptorsMapToBytes(Map<String, Object> roleDescriptorsMap) {
229-
try (XContentBuilder builder = XContentBuilder.builder(XContentType.JSON.xContent())) {
230-
builder.map(roleDescriptorsMap);
231-
return BytesReference.bytes(builder);
156+
/** Writes the authentication to the thread context */
157+
private void setAuthentication(Authentication authentication) {
158+
try {
159+
authentication.writeToContext(threadContext);
232160
} catch (IOException e) {
233-
throw new UncheckedIOException(e);
161+
throw new AssertionError("how can we have a IOException with a user we set", e);
234162
}
235163
}
236164
}

0 commit comments

Comments
 (0)