1010import org .apache .logging .log4j .Logger ;
1111import org .elasticsearch .ElasticsearchSecurityException ;
1212import org .elasticsearch .Version ;
13- import org .elasticsearch .common .bytes .BytesReference ;
1413import org .elasticsearch .common .settings .Settings ;
1514import org .elasticsearch .common .util .concurrent .ThreadContext ;
1615import org .elasticsearch .common .util .concurrent .ThreadContext .StoredContext ;
17- import org .elasticsearch .common .xcontent .XContentHelper ;
1816import org .elasticsearch .core .Nullable ;
1917import org .elasticsearch .node .Node ;
20- import org .elasticsearch .xcontent .XContentBuilder ;
21- import org .elasticsearch .xcontent .XContentType ;
2218import 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 ;
2519import org .elasticsearch .xpack .core .security .authc .support .AuthenticationContextSerializer ;
2620import org .elasticsearch .xpack .core .security .authc .support .SecondaryAuthentication ;
21+ import org .elasticsearch .xpack .core .security .user .SystemUser ;
2722import org .elasticsearch .xpack .core .security .user .User ;
2823
2924import java .io .IOException ;
3025import java .io .UncheckedIOException ;
31- import java .util .Collections ;
32- import java .util .HashMap ;
3326import java .util .Map ;
34- import java .util .Objects ;
3527import java .util .function .Consumer ;
3628import 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 */
4533public 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