diff --git a/benchmarks/src/main/java/io/druid/benchmark/query/SqlBenchmark.java b/benchmarks/src/main/java/io/druid/benchmark/query/SqlBenchmark.java index 8433a6b0d65e..132dd772d885 100644 --- a/benchmarks/src/main/java/io/druid/benchmark/query/SqlBenchmark.java +++ b/benchmarks/src/main/java/io/druid/benchmark/query/SqlBenchmark.java @@ -39,6 +39,7 @@ import io.druid.query.dimension.DimensionSpec; import io.druid.query.groupby.GroupByQuery; import io.druid.segment.QueryableIndex; +import io.druid.server.security.NoopEscalator; import io.druid.server.security.AuthConfig; import io.druid.server.security.AuthTestUtils; import io.druid.sql.calcite.planner.DruidPlanner; @@ -120,8 +121,8 @@ public void setup() throws Exception CalciteTests.createExprMacroTable(), plannerConfig, new AuthConfig(), - AuthTestUtils.TEST_AUTHENTICATOR_MAPPER, AuthTestUtils.TEST_AUTHORIZER_MAPPER, + new NoopEscalator(), CalciteTests.getJsonMapper() ); groupByQuery = GroupByQuery diff --git a/docs/content/configuration/auth.md b/docs/content/configuration/auth.md index 254bfb8221f9..358a54431b80 100644 --- a/docs/content/configuration/auth.md +++ b/docs/content/configuration/auth.md @@ -7,7 +7,7 @@ layout: doc_page |Property|Type|Description|Default|Required| |--------|-----------|--------|--------|--------| |`druid.auth.authenticationChain`|JSON List of Strings|List of Authenticator type names|["allowAll"]|no| -|`druid.auth.escalatedAuthenticator`|String|Type of the Authenticator that should be used for internal Druid communications. This Authenticator must be present in `druid.auth.authenticationChain`.|"allowAll"|no| +|`druid.escalator.type`|String|Type of the Escalator that should be used for internal Druid communications. This Escalator must use an authentication scheme that is supported by an Authenticator in `druid.auth.authenticationChain`.|"noop"|no| |`druid.auth.authorizers`|JSON List of Strings|List of Authorizer type names |["allowAll"]|no| ## Enabling Authentication/Authorization @@ -33,10 +33,14 @@ Druid includes a built-in Authenticator, used for the default unsecured configur This built-in Authenticator authenticates all requests, and always directs them to an Authorizer named "allowAll". It is not intended to be used for anything other than the default unsecured configuration. -## Internal Authenticator -The `druid.auth.escalatedAuthenticator` property determines what authentication scheme should be used for internal Druid cluster communications (such as when a broker node communicates with historical nodes for query processing). +## Escalator +The `druid.escalator.type` property determines what authentication scheme should be used for internal Druid cluster communications (such as when a broker node communicates with historical nodes for query processing). -The Authenticator chosen for this property must also be present in `druid.auth.authenticationChain`. +The Escalator chosen for this property must use an authentication scheme that is supported by an Authenticator in `druid.auth.authenticationChain. Authenticator extension implementors must also provide a corresponding Escalator implementation if they intend to use a particular authentication scheme for internal Druid communications. + +### Noop Escalator + +This built-in default Escalator is intended for use only with the default AllowAll Authenticator and Authorizer. ## Authorizers Authorization decisions are handled by an Authorizer. The `druid.auth.authorizers` property determines what Authorizer implementations will be active. @@ -63,7 +67,7 @@ When `druid.auth.authenticationChain` is left empty or unspecified, Druid will c When `druid.auth.authorizers` is left empty or unspecified, Druid will create a single AllowAll Authorizer named "allowAll". -The default value of `druid.auth.escalatedAuthenticator` is "allowAll" to match the default unsecured Authenticator/Authorizer configurations. +The default value of `druid.escalator.type` is "noop" to match the default unsecured Authenticator/Authorizer configurations. ## Authenticator to Authorizer Routing @@ -77,15 +81,17 @@ Internal requests between Druid nodes (non-user initiated communications) need t These requests should be run as an "internal system user", an identity that represents the Druid cluster itself, with full access permissions. -The details of how the internal system user is defined is left to Authorizer and Authenticator implementations. +The details of how the internal system user is defined is left to extension implementations. ### Authorizer Internal System User Handling Authorizers implementations must recognize and authorize an identity for the "internal system user", with full access permissions. -### Authenticator Internal System User Handling +### Authenticator and Escalator Internal System User Handling + +An Authenticator implementation that is intended to support internal Druid communications must recognize credentials for the "internal system user", as provided by a corresponding Escalator implementation. -Authenticators must implement three methods related to the internal system user: +An Escalator must implement three methods related to the internal system user: ```java public HttpClient createEscalatedClient(HttpClient baseClient); diff --git a/extensions-core/druid-kerberos/src/main/java/io/druid/security/kerberos/DruidKerberosModule.java b/extensions-core/druid-kerberos/src/main/java/io/druid/security/kerberos/DruidKerberosModule.java index e4058bc92d52..7685a0c7cb45 100644 --- a/extensions-core/druid-kerberos/src/main/java/io/druid/security/kerberos/DruidKerberosModule.java +++ b/extensions-core/druid-kerberos/src/main/java/io/druid/security/kerberos/DruidKerberosModule.java @@ -37,7 +37,8 @@ public List getJacksonModules() { return ImmutableList.of( new SimpleModule("DruidKerberos").registerSubtypes( - KerberosAuthenticator.class + KerberosAuthenticator.class, + KerberosEscalator.class ) ); } diff --git a/extensions-core/druid-kerberos/src/main/java/io/druid/security/kerberos/KerberosAuthenticator.java b/extensions-core/druid-kerberos/src/main/java/io/druid/security/kerberos/KerberosAuthenticator.java index 67d698b77334..785a5a415cb5 100644 --- a/extensions-core/druid-kerberos/src/main/java/io/druid/security/kerberos/KerberosAuthenticator.java +++ b/extensions-core/druid-kerberos/src/main/java/io/druid/security/kerberos/KerberosAuthenticator.java @@ -24,7 +24,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonTypeName; import com.google.common.base.Throwables; -import com.metamx.http.client.HttpClient; import io.druid.guice.annotations.Self; import io.druid.java.util.common.StringUtils; import io.druid.java.util.common.logger.Logger; @@ -34,7 +33,6 @@ import io.druid.server.security.Authenticator; import org.apache.commons.codec.binary.Base64; import org.apache.hadoop.security.SecurityUtil; -import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.authentication.client.AuthenticatedURL; import org.apache.hadoop.security.authentication.client.AuthenticationException; import org.apache.hadoop.security.authentication.server.AuthenticationFilter; @@ -43,11 +41,6 @@ import org.apache.hadoop.security.authentication.util.Signer; import org.apache.hadoop.security.authentication.util.SignerException; import org.apache.hadoop.security.authentication.util.SignerSecretProvider; -import org.eclipse.jetty.client.api.Authentication; -import org.eclipse.jetty.client.api.ContentResponse; -import org.eclipse.jetty.client.api.Request; -import org.eclipse.jetty.util.Attributes; -import org.jboss.netty.handler.codec.http.HttpHeaders; import sun.security.krb5.EncryptedData; import sun.security.krb5.EncryptionKey; import sun.security.krb5.internal.APReq; @@ -79,9 +72,7 @@ import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; -import java.net.URI; import java.security.Principal; -import java.security.PrivilegedExceptionAction; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; @@ -112,7 +103,6 @@ public class KerberosAuthenticator implements Authenticator private final String authorizerName; private LoginContext loginContext; - @JsonCreator public KerberosAuthenticator( @JsonProperty("serverPrincipal") String serverPrincipal, @@ -440,80 +430,6 @@ public AuthenticationResult authenticateJDBCContext(Map context) throw new UnsupportedOperationException("JDBC Kerberos auth not supported yet"); } - @Override - public HttpClient createEscalatedClient(HttpClient baseClient) - { - return new KerberosHttpClient(baseClient, internalClientPrincipal, internalClientKeytab); - } - - @Override - public org.eclipse.jetty.client.HttpClient createEscalatedJettyClient(org.eclipse.jetty.client.HttpClient baseClient) - { - baseClient.getAuthenticationStore().addAuthentication(new Authentication() - { - @Override - public boolean matches(String type, URI uri, String realm) - { - return true; - } - - @Override - public Result authenticate( - final Request request, ContentResponse response, Authentication.HeaderInfo headerInfo, Attributes context - ) - { - return new Result() - { - @Override - public URI getURI() - { - return request.getURI(); - } - - @Override - public void apply(Request request) - { - try { - // No need to set cookies as they are handled by Jetty Http Client itself. - URI uri = request.getURI(); - if (DruidKerberosUtil.needToSendCredentials(baseClient.getCookieStore(), uri)) { - log.debug( - "No Auth Cookie found for URI[%s]. Existing Cookies[%s] Authenticating... ", - uri, - baseClient.getCookieStore().getCookies() - ); - final String host = request.getHost(); - DruidKerberosUtil.authenticateIfRequired(internalClientPrincipal, internalClientKeytab); - UserGroupInformation currentUser = UserGroupInformation.getCurrentUser(); - String challenge = currentUser.doAs(new PrivilegedExceptionAction() - { - @Override - public String run() throws Exception - { - return DruidKerberosUtil.kerberosChallenge(host); - } - }); - request.getHeaders().add(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challenge); - } else { - log.debug("Found Auth Cookie found for URI[%s].", uri); - } - } - catch (Throwable e) { - Throwables.propagate(e); - } - } - }; - } - }); - return baseClient; - } - - @Override - public AuthenticationResult createEscalatedAuthenticationResult() - { - return new AuthenticationResult(internalClientPrincipal, authorizerName, null); - } - private boolean isExcluded(String path) { for (String excluded : excludedPaths) { diff --git a/extensions-core/druid-kerberos/src/main/java/io/druid/security/kerberos/KerberosEscalator.java b/extensions-core/druid-kerberos/src/main/java/io/druid/security/kerberos/KerberosEscalator.java new file mode 100644 index 000000000000..e995233a23c2 --- /dev/null +++ b/extensions-core/druid-kerberos/src/main/java/io/druid/security/kerberos/KerberosEscalator.java @@ -0,0 +1,134 @@ +/* + * Licensed to Metamarkets Group Inc. (Metamarkets) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Metamarkets licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.druid.security.kerberos; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.google.common.base.Throwables; +import com.metamx.http.client.HttpClient; +import io.druid.java.util.common.logger.Logger; +import io.druid.server.security.AuthenticationResult; +import io.druid.server.security.Escalator; +import org.apache.hadoop.security.UserGroupInformation; +import org.eclipse.jetty.client.api.Authentication; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.util.Attributes; +import org.jboss.netty.handler.codec.http.HttpHeaders; + +import java.net.URI; +import java.security.PrivilegedExceptionAction; + +@JsonTypeName("kerberos") +public class KerberosEscalator implements Escalator +{ + private static final Logger log = new Logger(KerberosAuthenticator.class); + + private final String internalClientPrincipal; + private final String internalClientKeytab; + private final String authorizerName; + + @JsonCreator + public KerberosEscalator( + @JsonProperty("authorizerName") String authorizerName, + @JsonProperty("internalClientPrincipal") String internalClientPrincipal, + @JsonProperty("internalClientKeytab") String internalClientKeytab + ) + { + this.authorizerName = authorizerName; + this.internalClientPrincipal = internalClientPrincipal; + this.internalClientKeytab = internalClientKeytab; + + } + @Override + public HttpClient createEscalatedClient(HttpClient baseClient) + { + return new KerberosHttpClient(baseClient, internalClientPrincipal, internalClientKeytab); + } + + @Override + public org.eclipse.jetty.client.HttpClient createEscalatedJettyClient(org.eclipse.jetty.client.HttpClient baseClient) + { + baseClient.getAuthenticationStore().addAuthentication(new Authentication() + { + @Override + public boolean matches(String type, URI uri, String realm) + { + return true; + } + + @Override + public Result authenticate( + final Request request, ContentResponse response, Authentication.HeaderInfo headerInfo, Attributes context + ) + { + return new Result() + { + @Override + public URI getURI() + { + return request.getURI(); + } + + @Override + public void apply(Request request) + { + try { + // No need to set cookies as they are handled by Jetty Http Client itself. + URI uri = request.getURI(); + if (DruidKerberosUtil.needToSendCredentials(baseClient.getCookieStore(), uri)) { + log.debug( + "No Auth Cookie found for URI[%s]. Existing Cookies[%s] Authenticating... ", + uri, + baseClient.getCookieStore().getCookies() + ); + final String host = request.getHost(); + DruidKerberosUtil.authenticateIfRequired(internalClientPrincipal, internalClientKeytab); + UserGroupInformation currentUser = UserGroupInformation.getCurrentUser(); + String challenge = currentUser.doAs(new PrivilegedExceptionAction() + { + @Override + public String run() throws Exception + { + return DruidKerberosUtil.kerberosChallenge(host); + } + }); + request.getHeaders().add(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challenge); + } else { + log.debug("Found Auth Cookie found for URI[%s].", uri); + } + } + catch (Throwable e) { + Throwables.propagate(e); + } + } + }; + } + }); + return baseClient; + } + + @Override + public AuthenticationResult createEscalatedAuthenticationResult() + { + return new AuthenticationResult(internalClientPrincipal, authorizerName, null); + } +} diff --git a/extensions-core/histogram/src/test/java/io/druid/query/aggregation/histogram/sql/QuantileSqlAggregatorTest.java b/extensions-core/histogram/src/test/java/io/druid/query/aggregation/histogram/sql/QuantileSqlAggregatorTest.java index 9f511b6f3abf..f74ab9541369 100644 --- a/extensions-core/histogram/src/test/java/io/druid/query/aggregation/histogram/sql/QuantileSqlAggregatorTest.java +++ b/extensions-core/histogram/src/test/java/io/druid/query/aggregation/histogram/sql/QuantileSqlAggregatorTest.java @@ -43,6 +43,7 @@ import io.druid.segment.column.ValueType; import io.druid.segment.incremental.IncrementalIndexSchema; import io.druid.segment.virtual.ExpressionVirtualColumn; +import io.druid.server.security.NoopEscalator; import io.druid.server.security.AuthConfig; import io.druid.server.security.AuthTestUtils; import io.druid.sql.calcite.filtration.Filtration; @@ -136,8 +137,8 @@ public void setUp() throws Exception CalciteTests.createExprMacroTable(), plannerConfig, new AuthConfig(), - AuthTestUtils.TEST_AUTHENTICATOR_MAPPER, AuthTestUtils.TEST_AUTHORIZER_MAPPER, + new NoopEscalator(), CalciteTests.getJsonMapper() ); } diff --git a/server/src/main/java/io/druid/guice/http/HttpClientModule.java b/server/src/main/java/io/druid/guice/http/HttpClientModule.java index 848bb9b3eb8f..73b06163c0ce 100644 --- a/server/src/main/java/io/druid/guice/http/HttpClientModule.java +++ b/server/src/main/java/io/druid/guice/http/HttpClientModule.java @@ -32,8 +32,7 @@ import io.druid.guice.annotations.EscalatedGlobal; import io.druid.guice.annotations.Global; import io.druid.java.util.common.StringUtils; -import io.druid.server.security.Authenticator; -import io.druid.server.security.AuthenticatorMapper; +import io.druid.server.security.Escalator; import java.lang.annotation.Annotation; import java.util.Set; @@ -106,7 +105,7 @@ public void configure(Binder binder) public static class HttpClientProvider extends AbstractHttpClientProvider { private boolean isEscalated; - private Authenticator escalatingAuthenticator; + private Escalator escalator; public HttpClientProvider(boolean isEscalated) { @@ -126,9 +125,9 @@ public HttpClientProvider(Class annotationClazz, boolean i } @Inject - public void inject(AuthenticatorMapper authenticatorMapper) + public void inject(Escalator escalator) { - this.escalatingAuthenticator = authenticatorMapper.getEscalatingAuthenticator(); + this.escalator = escalator; } @Override @@ -155,7 +154,7 @@ public HttpClient get() ); if (isEscalated) { - return escalatingAuthenticator.createEscalatedClient(client); + return escalator.createEscalatedClient(client); } else { return client; } diff --git a/server/src/main/java/io/druid/guice/security/AuthenticatorModule.java b/server/src/main/java/io/druid/guice/security/AuthenticatorModule.java index 7c09284ef52f..117758f07f7c 100644 --- a/server/src/main/java/io/druid/guice/security/AuthenticatorModule.java +++ b/server/src/main/java/io/druid/guice/security/AuthenticatorModule.java @@ -27,8 +27,9 @@ import com.google.inject.name.Named; import io.druid.guice.LazySingleton; import io.druid.guice.PolyBind; -import io.druid.server.security.Authenticator; import io.druid.server.security.AllowAllAuthenticator; +import io.druid.server.security.AuthConfig; +import io.druid.server.security.Authenticator; public class AuthenticatorModule implements Module { @@ -39,11 +40,13 @@ public void configure(Binder binder) binder, Key.get(Authenticator.class) ); - authenticatorMapBinder.addBinding("allowAll").to(AllowAllAuthenticator.class).in(LazySingleton.class); + authenticatorMapBinder.addBinding(AuthConfig.ALLOW_ALL_NAME) + .to(AllowAllAuthenticator.class) + .in(LazySingleton.class); } @Provides - @Named("allowAll") + @Named(AuthConfig.ALLOW_ALL_NAME) public Authenticator getAuthenticator() { return new AllowAllAuthenticator(); diff --git a/server/src/main/java/io/druid/guice/security/AuthorizerModule.java b/server/src/main/java/io/druid/guice/security/AuthorizerModule.java index a39a3dc09462..4deef3b65b28 100644 --- a/server/src/main/java/io/druid/guice/security/AuthorizerModule.java +++ b/server/src/main/java/io/druid/guice/security/AuthorizerModule.java @@ -27,8 +27,9 @@ import com.google.inject.name.Named; import io.druid.guice.LazySingleton; import io.druid.guice.PolyBind; -import io.druid.server.security.Authorizer; import io.druid.server.security.AllowAllAuthorizer; +import io.druid.server.security.AuthConfig; +import io.druid.server.security.Authorizer; public class AuthorizerModule implements Module { @@ -39,11 +40,11 @@ public void configure(Binder binder) binder, Key.get(Authorizer.class) ); - authorizerMapBinder.addBinding("allowAll").to(AllowAllAuthorizer.class).in(LazySingleton.class); + authorizerMapBinder.addBinding(AuthConfig.ALLOW_ALL_NAME).to(AllowAllAuthorizer.class).in(LazySingleton.class); } @Provides - @Named("allowAll") + @Named(AuthConfig.ALLOW_ALL_NAME) public Authorizer getAuthorizer() { return new AllowAllAuthorizer(); diff --git a/server/src/main/java/io/druid/guice/security/EscalatorModule.java b/server/src/main/java/io/druid/guice/security/EscalatorModule.java new file mode 100644 index 000000000000..7e0b719966b0 --- /dev/null +++ b/server/src/main/java/io/druid/guice/security/EscalatorModule.java @@ -0,0 +1,34 @@ +/* + * Licensed to Metamarkets Group Inc. (Metamarkets) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Metamarkets licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.druid.guice.security; + +import com.google.inject.Binder; +import com.google.inject.Module; +import io.druid.guice.JsonConfigProvider; +import io.druid.server.security.Escalator; + +public class EscalatorModule implements Module +{ + @Override + public void configure(Binder binder) + { + JsonConfigProvider.bind(binder, "druid.escalator", Escalator.class); + } +} diff --git a/server/src/main/java/io/druid/initialization/Initialization.java b/server/src/main/java/io/druid/initialization/Initialization.java index a6ab2a0d155c..81ef5e2fdc31 100644 --- a/server/src/main/java/io/druid/initialization/Initialization.java +++ b/server/src/main/java/io/druid/initialization/Initialization.java @@ -60,13 +60,13 @@ import io.druid.guice.security.AuthenticatorModule; import io.druid.guice.security.AuthorizerModule; import io.druid.guice.security.DruidAuthModule; +import io.druid.guice.security.EscalatorModule; import io.druid.java.util.common.ISE; import io.druid.java.util.common.logger.Logger; import io.druid.metadata.storage.derby.DerbyMetadataStorageDruidModule; -import io.druid.server.initialization.AuthenticatorHttpClientWrapperModule; +import io.druid.server.emitter.EmitterModule; import io.druid.server.initialization.AuthenticatorMapperModule; import io.druid.server.initialization.AuthorizerMapperModule; -import io.druid.server.emitter.EmitterModule; import io.druid.server.initialization.jetty.JettyServerModule; import io.druid.server.metrics.MetricsModule; import org.apache.commons.io.FileUtils; @@ -378,7 +378,7 @@ public static Injector makeInjectorWithModules(final Injector baseInjector, Iter new JavaScriptModule(), new AuthenticatorModule(), new AuthenticatorMapperModule(), - new AuthenticatorHttpClientWrapperModule(), + new EscalatorModule(), new AuthorizerModule(), new AuthorizerMapperModule(), new StartupLoggingModule() diff --git a/server/src/main/java/io/druid/server/AsyncQueryForwardingServlet.java b/server/src/main/java/io/druid/server/AsyncQueryForwardingServlet.java index d16673660e93..b6c5f287235f 100644 --- a/server/src/main/java/io/druid/server/AsyncQueryForwardingServlet.java +++ b/server/src/main/java/io/druid/server/AsyncQueryForwardingServlet.java @@ -44,8 +44,7 @@ import io.druid.server.router.QueryHostFinder; import io.druid.server.router.Router; import io.druid.server.security.AuthConfig; -import io.druid.server.security.Authenticator; -import io.druid.server.security.AuthenticatorMapper; +import io.druid.server.security.Escalator; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Response; @@ -114,7 +113,7 @@ private static void handleException(HttpServletResponse response, ObjectMapper o private final ServiceEmitter emitter; private final RequestLogger requestLogger; private final GenericQueryMetricsFactory queryMetricsFactory; - private final Authenticator escalatingAuthenticator; + private final Escalator escalator; private HttpClient broadcastClient; @@ -129,7 +128,7 @@ public AsyncQueryForwardingServlet( ServiceEmitter emitter, RequestLogger requestLogger, GenericQueryMetricsFactory queryMetricsFactory, - AuthenticatorMapper authenticatorMapper + Escalator escalator ) { this.warehouse = warehouse; @@ -141,7 +140,7 @@ public AsyncQueryForwardingServlet( this.emitter = emitter; this.requestLogger = requestLogger; this.queryMetricsFactory = queryMetricsFactory; - this.escalatingAuthenticator = authenticatorMapper.getEscalatingAuthenticator(); + this.escalator = escalator; } @Override @@ -349,7 +348,7 @@ protected static URI makeURI(String scheme, String host, String requestURI, Stri @Override protected HttpClient newHttpClient() { - return escalatingAuthenticator.createEscalatedJettyClient(httpClientProvider.get()); + return escalator.createEscalatedJettyClient(httpClientProvider.get()); } @Override diff --git a/server/src/main/java/io/druid/server/initialization/AuthenticatorHttpClientWrapperModule.java b/server/src/main/java/io/druid/server/initialization/AuthenticatorHttpClientWrapperModule.java deleted file mode 100644 index 78f88fe8eb91..000000000000 --- a/server/src/main/java/io/druid/server/initialization/AuthenticatorHttpClientWrapperModule.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to Metamarkets Group Inc. (Metamarkets) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. Metamarkets licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package io.druid.server.initialization; - -import com.fasterxml.jackson.databind.Module; -import com.google.inject.Binder; -import com.google.inject.Inject; -import com.google.inject.Provider; -import io.druid.guice.LazySingleton; -import io.druid.initialization.DruidModule; -import io.druid.java.util.common.logger.Logger; -import io.druid.server.security.AuthenticatorHttpClientWrapper; -import io.druid.server.security.AuthenticatorMapper; - -import java.util.Collections; -import java.util.List; - -public class AuthenticatorHttpClientWrapperModule implements DruidModule -{ - private static Logger log = new Logger(AuthenticatorHttpClientWrapperModule.class); - - @Override - public void configure(Binder binder) - { - binder.bind(AuthenticatorHttpClientWrapper.class) - .toProvider(new AuthenticatorHttpClientWrapperProvider()) - .in(LazySingleton.class); - } - - @Override - public List getJacksonModules() - { - return Collections.EMPTY_LIST; - } - - private static class AuthenticatorHttpClientWrapperProvider implements Provider - { - private AuthenticatorHttpClientWrapper wrapper; - - @Inject - public void inject(AuthenticatorMapper authenticatorMapper) - { - this.wrapper = new AuthenticatorHttpClientWrapper(authenticatorMapper.getEscalatingAuthenticator()); - } - - @Override - public AuthenticatorHttpClientWrapper get() - { - return wrapper; - } - } -} diff --git a/server/src/main/java/io/druid/server/initialization/AuthenticatorMapperModule.java b/server/src/main/java/io/druid/server/initialization/AuthenticatorMapperModule.java index cb8ccbedfaf7..d7085721ceb9 100644 --- a/server/src/main/java/io/druid/server/initialization/AuthenticatorMapperModule.java +++ b/server/src/main/java/io/druid/server/initialization/AuthenticatorMapperModule.java @@ -41,9 +41,11 @@ import io.druid.server.security.AllowAllAuthenticator; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.Set; public class AuthenticatorMapperModule implements DruidModule { @@ -91,14 +93,12 @@ public AuthenticatorMapper get() List authenticators = authConfig.getAuthenticatorChain(); + validateAuthenticators(authenticators); + // Default configuration is to allow all requests. if (authenticators == null) { - authenticatorMap.put("allowAll", new AllowAllAuthenticator()); - return new AuthenticatorMapper(authenticatorMap, "allowAll"); - } - - if (authenticators.isEmpty()) { - throw new IAE("Must have at least one Authenticator configured."); + authenticatorMap.put(AuthConfig.ALLOW_ALL_NAME, new AllowAllAuthenticator()); + return new AuthenticatorMapper(authenticatorMap); } for (String authenticatorName : authenticators) { @@ -125,7 +125,26 @@ public AuthenticatorMapper get() authenticatorMap.put(authenticatorName, authenticator); } - return new AuthenticatorMapper(authenticatorMap, authConfig.getEscalatedAuthenticator()); + return new AuthenticatorMapper(authenticatorMap); + } + } + + private static void validateAuthenticators(List authenticators) + { + if (authenticators == null) { + return; + } + + if (authenticators.isEmpty()) { + throw new IAE("Must have at least one Authenticator configured."); + } + + Set authenticatorSet = new HashSet<>(); + for (String authenticator : authenticators) { + if (authenticatorSet.contains(authenticator)) { + throw new ISE("Cannot have multiple authenticators with the same name: [%s]", authenticator); + } + authenticatorSet.add(authenticator); } } } diff --git a/server/src/main/java/io/druid/server/initialization/AuthorizerMapperModule.java b/server/src/main/java/io/druid/server/initialization/AuthorizerMapperModule.java index 6da287a648ea..4ba019550833 100644 --- a/server/src/main/java/io/druid/server/initialization/AuthorizerMapperModule.java +++ b/server/src/main/java/io/druid/server/initialization/AuthorizerMapperModule.java @@ -41,9 +41,11 @@ import io.druid.server.security.AuthorizerMapper; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.Set; public class AuthorizerMapperModule implements DruidModule { @@ -89,6 +91,8 @@ public AuthorizerMapper get() Map authorizerMap = Maps.newHashMap(); List authorizers = authConfig.getAuthorizers(); + validateAuthorizers(authorizers); + // Default is allow all if (authorizers == null) { return new AuthorizerMapper(null) { @@ -100,10 +104,6 @@ public Authorizer getAuthorizer(String name) }; } - if (authorizers.isEmpty()) { - throw new IAE("Must have at least one Authorizer configured."); - } - for (String authorizerName : authorizers) { final String authorizerPropertyBase = StringUtils.format(AUTHORIZER_PROPERTIES_FORMAT_STRING, authorizerName); final JsonConfigProvider authorizerProvider = new JsonConfigProvider<>( @@ -132,4 +132,23 @@ public Authorizer getAuthorizer(String name) return new AuthorizerMapper(authorizerMap); } } + + private static void validateAuthorizers(List authorizers) + { + if (authorizers == null) { + return; + } + + if (authorizers.isEmpty()) { + throw new IAE("Must have at least one Authorizer configured."); + } + + Set authorizerSet = new HashSet<>(); + for (String authorizer : authorizers) { + if (authorizerSet.contains(authorizer)) { + throw new ISE("Cannot have multiple authorizers with the same name: [%s]", authorizer); + } + authorizerSet.add(authorizer); + } + } } diff --git a/server/src/main/java/io/druid/server/security/AllowAllAuthenticator.java b/server/src/main/java/io/druid/server/security/AllowAllAuthenticator.java index cae5a4f01ac6..c87d67546ae2 100644 --- a/server/src/main/java/io/druid/server/security/AllowAllAuthenticator.java +++ b/server/src/main/java/io/druid/server/security/AllowAllAuthenticator.java @@ -19,8 +19,6 @@ package io.druid.server.security; -import com.metamx.http.client.HttpClient; - import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.FilterChain; @@ -37,7 +35,11 @@ */ public class AllowAllAuthenticator implements Authenticator { - public static final AuthenticationResult ALLOW_ALL_RESULT = new AuthenticationResult("allowAll", "allowAll", null); + public static final AuthenticationResult ALLOW_ALL_RESULT = new AuthenticationResult( + AuthConfig.ALLOW_ALL_NAME, + AuthConfig.ALLOW_ALL_NAME, + null + ); @Override public Class getFilterClass() @@ -102,22 +104,4 @@ public AuthenticationResult authenticateJDBCContext(Map context) { return ALLOW_ALL_RESULT; } - - @Override - public HttpClient createEscalatedClient(HttpClient baseClient) - { - return baseClient; - } - - @Override - public org.eclipse.jetty.client.HttpClient createEscalatedJettyClient(org.eclipse.jetty.client.HttpClient baseClient) - { - return baseClient; - } - - @Override - public AuthenticationResult createEscalatedAuthenticationResult() - { - return ALLOW_ALL_RESULT; - } } diff --git a/server/src/main/java/io/druid/server/security/AuthConfig.java b/server/src/main/java/io/druid/server/security/AuthConfig.java index e93d84939706..af4768a4d5e0 100644 --- a/server/src/main/java/io/druid/server/security/AuthConfig.java +++ b/server/src/main/java/io/druid/server/security/AuthConfig.java @@ -36,29 +36,26 @@ public class AuthConfig */ public static final String DRUID_AUTHORIZATION_CHECKED = "Druid-Authorization-Checked"; + public static final String ALLOW_ALL_NAME = "allowAll"; + public AuthConfig() { - this(null, null, null); + this(null, null); } @JsonCreator public AuthConfig( @JsonProperty("authenticatorChain") List authenticationChain, - @JsonProperty("escalatedAuthenticator") String escalatedAuthenticator, @JsonProperty("authorizers") List authorizers ) { this.authenticatorChain = authenticationChain; - this.escalatedAuthenticator = escalatedAuthenticator == null ? "allowAll" : escalatedAuthenticator; this.authorizers = authorizers; } @JsonProperty private final List authenticatorChain; - @JsonProperty - private final String escalatedAuthenticator; - @JsonProperty private List authorizers; @@ -67,11 +64,6 @@ public List getAuthenticatorChain() return authenticatorChain; } - public String getEscalatedAuthenticator() - { - return escalatedAuthenticator; - } - public List getAuthorizers() { return authorizers; @@ -82,7 +74,6 @@ public String toString() { return "AuthConfig{" + "authenticatorChain='" + authenticatorChain + '\'' + - ", escalatedAuthenticator='" + escalatedAuthenticator + '\'' + ", authorizers='" + authorizers + '\'' + '}'; } @@ -104,11 +95,6 @@ public boolean equals(Object o) : that.getAuthenticatorChain() != null) { return false; } - if (getEscalatedAuthenticator() != null - ? !getEscalatedAuthenticator().equals(that.getEscalatedAuthenticator()) - : that.getEscalatedAuthenticator() != null) { - return false; - } return getAuthorizers() != null ? getAuthorizers().equals(that.getAuthorizers()) : that.getAuthorizers() == null; } @@ -117,7 +103,6 @@ public boolean equals(Object o) public int hashCode() { int result = getAuthenticatorChain() != null ? getAuthenticatorChain().hashCode() : 0; - result = 31 * result + (getEscalatedAuthenticator() != null ? getEscalatedAuthenticator().hashCode() : 0); result = 31 * result + (getAuthorizers() != null ? getAuthorizers().hashCode() : 0); return result; } diff --git a/server/src/main/java/io/druid/server/security/AuthTestUtils.java b/server/src/main/java/io/druid/server/security/AuthTestUtils.java index e06fa9c23030..71fac1e5aeed 100644 --- a/server/src/main/java/io/druid/server/security/AuthTestUtils.java +++ b/server/src/main/java/io/druid/server/security/AuthTestUtils.java @@ -30,8 +30,8 @@ public class AuthTestUtils static { final Map defaultMap = Maps.newHashMap(); - defaultMap.put("allowAll", new AllowAllAuthenticator()); - TEST_AUTHENTICATOR_MAPPER = new AuthenticatorMapper(defaultMap, "allowAll"); + defaultMap.put(AuthConfig.ALLOW_ALL_NAME, new AllowAllAuthenticator()); + TEST_AUTHENTICATOR_MAPPER = new AuthenticatorMapper(defaultMap); TEST_AUTHORIZER_MAPPER = new AuthorizerMapper(null) { @Override diff --git a/server/src/main/java/io/druid/server/security/Authenticator.java b/server/src/main/java/io/druid/server/security/Authenticator.java index d4db90b21733..969b4497f2a5 100644 --- a/server/src/main/java/io/druid/server/security/Authenticator.java +++ b/server/src/main/java/io/druid/server/security/Authenticator.java @@ -21,7 +21,6 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.metamx.http.client.HttpClient; import io.druid.server.initialization.jetty.ServletFilterHolder; import javax.annotation.Nullable; @@ -30,17 +29,13 @@ @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonSubTypes(value = { - @JsonSubTypes.Type(name = "allowAll", value = AllowAllAuthenticator.class), + @JsonSubTypes.Type(name = AuthConfig.ALLOW_ALL_NAME, value = AllowAllAuthenticator.class), }) /** * This interface is essentially a ServletFilterHolder with additional requirements on the getFilter() method contract, plus: * * - A method that returns a WWW-Authenticate challenge header appropriate for the * authentication mechanism, getAuthChallengeHeader(). - * - A method for creating a wrapped HTTP client that can authenticate using the Authenticator's authentication scheme, - * used for internal Druid node communications (e.g., broker -> historical messages), createEscalatedClient(). - * - A method for creating a wrapped Jetty HTTP client that can authenticate using the Authenticator's authentication scheme, - * used by the Druid router, createEscalatedJettyClient(). * - A method for authenticating credentials contained in a JDBC connection context, used for authenticating Druid SQL * requests received via JDBC, authenticateJDBCContext(). */ @@ -98,34 +93,4 @@ public interface Authenticator extends ServletFilterHolder */ @Nullable AuthenticationResult authenticateJDBCContext(Map context); - - /** - * Return a client that sends requests with the format/information necessary to authenticate successfully - * against this Authenticator's authentication scheme using the identity of the internal system user. - *

- * This HTTP client is used for internal communications between Druid nodes, such as when a broker communicates - * with a historical node during query processing. - * - * @param baseClient Base HTTP client for internal Druid communications - * - * @return metamx HttpClient that sends requests with the credentials of the internal system user - */ - HttpClient createEscalatedClient(HttpClient baseClient); - - /** - * Return a client that sends requests with the format/information necessary to authenticate successfully - * against this Authenticator's authentication scheme using the identity of the internal system user. - *

- * This HTTP client is used by the Druid Router node. - * - * @param baseClient Base Jetty HttpClient - * - * @return Jetty HttpClient that sends requests with the credentials of the internal system user - */ - org.eclipse.jetty.client.HttpClient createEscalatedJettyClient(org.eclipse.jetty.client.HttpClient baseClient); - - /** - * @return an AuthenticationResult representing the identity of the internal system user. - */ - AuthenticationResult createEscalatedAuthenticationResult(); } diff --git a/server/src/main/java/io/druid/server/security/AuthenticatorMapper.java b/server/src/main/java/io/druid/server/security/AuthenticatorMapper.java index 952f607cbaf8..852b7e4a3105 100644 --- a/server/src/main/java/io/druid/server/security/AuthenticatorMapper.java +++ b/server/src/main/java/io/druid/server/security/AuthenticatorMapper.java @@ -19,7 +19,6 @@ package io.druid.server.security; -import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import io.druid.guice.ManageLifecycle; @@ -30,25 +29,12 @@ public class AuthenticatorMapper { private Map authenticatorMap; - private Authenticator escalatingAuthenticator; public AuthenticatorMapper( - Map authenticatorMap, - String escalatingAuthenticatorName + Map authenticatorMap ) { this.authenticatorMap = authenticatorMap; - this.escalatingAuthenticator = authenticatorMap.get(escalatingAuthenticatorName); - Preconditions.checkNotNull( - escalatingAuthenticator, - "Could not find escalating authenticator with name: %s", - escalatingAuthenticatorName - ); - } - - public Authenticator getEscalatingAuthenticator() - { - return escalatingAuthenticator; } public List getAuthenticatorChain() diff --git a/server/src/main/java/io/druid/server/security/Authorizer.java b/server/src/main/java/io/druid/server/security/Authorizer.java index 9cd586c9f9dc..cade33eee406 100644 --- a/server/src/main/java/io/druid/server/security/Authorizer.java +++ b/server/src/main/java/io/druid/server/security/Authorizer.java @@ -24,7 +24,7 @@ @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonSubTypes(value = { - @JsonSubTypes.Type(name = "allowAll", value = AllowAllAuthorizer.class) + @JsonSubTypes.Type(name = AuthConfig.ALLOW_ALL_NAME, value = AllowAllAuthorizer.class) }) /** * An Authorizer is responsible for performing authorization checks for resource accesses. diff --git a/server/src/main/java/io/druid/server/security/Escalator.java b/server/src/main/java/io/druid/server/security/Escalator.java new file mode 100644 index 000000000000..021572ed3f0a --- /dev/null +++ b/server/src/main/java/io/druid/server/security/Escalator.java @@ -0,0 +1,65 @@ +/* + * Licensed to Metamarkets Group Inc. (Metamarkets) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Metamarkets licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.druid.server.security; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.metamx.http.client.HttpClient; + +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", defaultImpl = NoopEscalator.class) +@JsonSubTypes(value = { + @JsonSubTypes.Type(name = "noop", value = NoopEscalator.class), +}) +/** + * This interface provides methods needed for escalating internal system requests with priveleged authentication + * credentials. Each Escalator is associated with a specific authentication scheme, like Authenticators. + */ +public interface Escalator +{ + /** + * Return a client that sends requests with the format/information necessary to authenticate successfully + * against this Escalator's authentication scheme using the identity of the internal system user. + *

+ * This HTTP client is used for internal communications between Druid nodes, such as when a broker communicates + * with a historical node during query processing. + * + * @param baseClient Base HTTP client for internal Druid communications + * + * @return metamx HttpClient that sends requests with the credentials of the internal system user + */ + HttpClient createEscalatedClient(HttpClient baseClient); + + /** + * Return a client that sends requests with the format/information necessary to authenticate successfully + * against this Authenticator's authentication scheme using the identity of the internal system user. + *

+ * This HTTP client is used by the Druid Router node. + * + * @param baseClient Base Jetty HttpClient + * + * @return Jetty HttpClient that sends requests with the credentials of the internal system user + */ + org.eclipse.jetty.client.HttpClient createEscalatedJettyClient(org.eclipse.jetty.client.HttpClient baseClient); + + /** + * @return an AuthenticationResult representing the identity of the internal system user. + */ + AuthenticationResult createEscalatedAuthenticationResult(); +} diff --git a/server/src/main/java/io/druid/server/security/AuthenticatorHttpClientWrapper.java b/server/src/main/java/io/druid/server/security/NoopEscalator.java similarity index 63% rename from server/src/main/java/io/druid/server/security/AuthenticatorHttpClientWrapper.java rename to server/src/main/java/io/druid/server/security/NoopEscalator.java index 25d4cb7c3d25..583d12dc249a 100644 --- a/server/src/main/java/io/druid/server/security/AuthenticatorHttpClientWrapper.java +++ b/server/src/main/java/io/druid/server/security/NoopEscalator.java @@ -21,23 +21,23 @@ import com.metamx.http.client.HttpClient; -/** - * Singleton utility object that creates escalated HttpClients using a configuration-specified Authenticator's - * getEscalatedClient() method. - */ -public class AuthenticatorHttpClientWrapper +public class NoopEscalator implements Escalator { - private Authenticator escalatingAuthenticator; + @Override + public HttpClient createEscalatedClient(HttpClient baseClient) + { + return baseClient; + } - public AuthenticatorHttpClientWrapper( - final Authenticator escalatingAuthenticator - ) + @Override + public org.eclipse.jetty.client.HttpClient createEscalatedJettyClient(org.eclipse.jetty.client.HttpClient baseClient) { - this.escalatingAuthenticator = escalatingAuthenticator; + return baseClient; } - public HttpClient getEscalatedClient(HttpClient baseClient) + @Override + public AuthenticationResult createEscalatedAuthenticationResult() { - return escalatingAuthenticator.createEscalatedClient(baseClient); + return AllowAllAuthenticator.ALLOW_ALL_RESULT; } } diff --git a/server/src/test/java/io/druid/server/AsyncQueryForwardingServletTest.java b/server/src/test/java/io/druid/server/AsyncQueryForwardingServletTest.java index 329ac6688c8f..c1c0d3b2a4ed 100644 --- a/server/src/test/java/io/druid/server/AsyncQueryForwardingServletTest.java +++ b/server/src/test/java/io/druid/server/AsyncQueryForwardingServletTest.java @@ -52,7 +52,7 @@ import io.druid.server.router.QueryHostFinder; import io.druid.server.router.RendezvousHashAvaticaConnectionBalancer; import io.druid.server.security.AllowAllAuthorizer; -import io.druid.server.security.AuthTestUtils; +import io.druid.server.security.NoopEscalator; import io.druid.server.security.Authorizer; import io.druid.server.security.AuthorizerMapper; import org.eclipse.jetty.client.HttpClient; @@ -253,7 +253,7 @@ public void log(RequestLogLine requestLogLine) throws IOException } }, new DefaultGenericQueryMetricsFactory(jsonMapper), - AuthTestUtils.TEST_AUTHENTICATOR_MAPPER + new NoopEscalator() ) { @Override diff --git a/server/src/test/java/io/druid/server/QueryResourceTest.java b/server/src/test/java/io/druid/server/QueryResourceTest.java index 15742dc786ed..c07002b05e98 100644 --- a/server/src/test/java/io/druid/server/QueryResourceTest.java +++ b/server/src/test/java/io/druid/server/QueryResourceTest.java @@ -247,13 +247,13 @@ public Access authorize(AuthenticationResult authenticationResult, Resource reso new DefaultGenericQueryMetricsFactory(jsonMapper), new NoopServiceEmitter(), testRequestLogger, - new AuthConfig(null, null, null), + new AuthConfig(null, null), authMapper ), jsonMapper, jsonMapper, queryManager, - new AuthConfig(null, null, null), + new AuthConfig(null, null), authMapper, new DefaultGenericQueryMetricsFactory(jsonMapper) ); @@ -354,13 +354,13 @@ public Access authorize(AuthenticationResult authenticationResult, Resource reso new DefaultGenericQueryMetricsFactory(jsonMapper), new NoopServiceEmitter(), testRequestLogger, - new AuthConfig(null, null, null), + new AuthConfig(null, null), authMapper ), jsonMapper, jsonMapper, queryManager, - new AuthConfig(null, null, null), + new AuthConfig(null, null), authMapper, new DefaultGenericQueryMetricsFactory(jsonMapper) ); @@ -475,13 +475,13 @@ public Access authorize(AuthenticationResult authenticationResult, Resource reso new DefaultGenericQueryMetricsFactory(jsonMapper), new NoopServiceEmitter(), testRequestLogger, - new AuthConfig(null, null, null), + new AuthConfig(null, null), authMapper ), jsonMapper, jsonMapper, queryManager, - new AuthConfig(null, null, null), + new AuthConfig(null, null), authMapper, new DefaultGenericQueryMetricsFactory(jsonMapper) ); diff --git a/server/src/test/java/io/druid/server/http/DatasourcesResourceTest.java b/server/src/test/java/io/druid/server/http/DatasourcesResourceTest.java index 315bfb0b4876..96e0b583f2e0 100644 --- a/server/src/test/java/io/druid/server/http/DatasourcesResourceTest.java +++ b/server/src/test/java/io/druid/server/http/DatasourcesResourceTest.java @@ -236,7 +236,7 @@ public Access authorize(AuthenticationResult authenticationResult1, Resource res inventoryView, null, null, - new AuthConfig(null, null, null), + new AuthConfig(null, null), authMapper ); Response response = datasourcesResource.getQueryableDataSources("full", null, request); diff --git a/server/src/test/java/io/druid/server/http/security/ResourceFilterTestHelper.java b/server/src/test/java/io/druid/server/http/security/ResourceFilterTestHelper.java index 2ca7b311ee59..ed39de6452ef 100644 --- a/server/src/test/java/io/druid/server/http/security/ResourceFilterTestHelper.java +++ b/server/src/test/java/io/druid/server/http/security/ResourceFilterTestHelper.java @@ -182,7 +182,7 @@ public void configure(Binder binder) for (Key key : mockableKeys) { binder.bind((Key) key).toInstance(EasyMock.createNiceMock(key.getTypeLiteral().getRawType())); } - binder.bind(AuthConfig.class).toInstance(new AuthConfig(null, null, null)); + binder.bind(AuthConfig.class).toInstance(new AuthConfig(null, null)); } } ); diff --git a/sql/src/main/java/io/druid/sql/avatica/DruidStatement.java b/sql/src/main/java/io/druid/sql/avatica/DruidStatement.java index cd1d0f932cd4..86048980d77d 100644 --- a/sql/src/main/java/io/druid/sql/avatica/DruidStatement.java +++ b/sql/src/main/java/io/druid/sql/avatica/DruidStatement.java @@ -22,9 +22,9 @@ import com.google.common.base.Preconditions; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableMap; -import io.druid.java.util.common.concurrent.Execs; import io.druid.java.util.common.ISE; import io.druid.java.util.common.StringUtils; +import io.druid.java.util.common.concurrent.Execs; import io.druid.java.util.common.guava.Sequence; import io.druid.java.util.common.guava.Sequences; import io.druid.java.util.common.guava.Yielder; diff --git a/sql/src/main/java/io/druid/sql/calcite/planner/DruidPlanner.java b/sql/src/main/java/io/druid/sql/calcite/planner/DruidPlanner.java index cfd085b68c74..8779d793e067 100644 --- a/sql/src/main/java/io/druid/sql/calcite/planner/DruidPlanner.java +++ b/sql/src/main/java/io/druid/sql/calcite/planner/DruidPlanner.java @@ -30,9 +30,9 @@ import io.druid.server.security.Access; import io.druid.server.security.AuthConfig; import io.druid.server.security.AuthenticationResult; -import io.druid.server.security.AuthenticatorMapper; import io.druid.server.security.AuthorizationUtils; import io.druid.server.security.AuthorizerMapper; +import io.druid.server.security.Escalator; import io.druid.server.security.ForbiddenException; import io.druid.sql.calcite.rel.DruidConvention; import io.druid.sql.calcite.rel.DruidRel; @@ -71,29 +71,25 @@ public class DruidPlanner implements Closeable { private final Planner planner; private final PlannerContext plannerContext; - private final AuthConfig authConfig; private final AuthorizerMapper authorizerMapper; - private final AuthenticatorMapper authenticatorMapper; + private final Escalator escalator; public DruidPlanner( final Planner planner, final PlannerContext plannerContext, - final AuthConfig authConfig, final AuthorizerMapper authorizerMapper, - final AuthenticatorMapper authenticatorMapper + final Escalator escalator ) { this.planner = planner; this.plannerContext = plannerContext; - this.authConfig = authConfig; this.authorizerMapper = authorizerMapper; - this.authenticatorMapper = authenticatorMapper; + this.escalator = escalator; } public PlannerResult plan(final String sql) throws SqlParseException, ValidationException, RelConversionException { - AuthenticationResult authenticationResult = authenticatorMapper.getEscalatingAuthenticator() - .createEscalatedAuthenticationResult(); + AuthenticationResult authenticationResult = escalator.createEscalatedAuthenticationResult(); return plan(sql, null, authenticationResult); } diff --git a/sql/src/main/java/io/druid/sql/calcite/planner/PlannerFactory.java b/sql/src/main/java/io/druid/sql/calcite/planner/PlannerFactory.java index bfbc755a9769..843003c0b45f 100644 --- a/sql/src/main/java/io/druid/sql/calcite/planner/PlannerFactory.java +++ b/sql/src/main/java/io/druid/sql/calcite/planner/PlannerFactory.java @@ -25,8 +25,8 @@ import io.druid.math.expr.ExprMacroTable; import io.druid.server.QueryLifecycleFactory; import io.druid.server.security.AuthConfig; -import io.druid.server.security.AuthenticatorMapper; import io.druid.server.security.AuthorizerMapper; +import io.druid.server.security.Escalator; import io.druid.sql.calcite.rel.QueryMaker; import io.druid.sql.calcite.schema.DruidSchema; import org.apache.calcite.avatica.util.Casing; @@ -67,7 +67,7 @@ public class PlannerFactory private final AuthConfig authConfig; private final AuthorizerMapper authorizerMapper; - private final AuthenticatorMapper authenticatorMapper; + private final Escalator escalator; @Inject public PlannerFactory( @@ -77,8 +77,8 @@ public PlannerFactory( final ExprMacroTable macroTable, final PlannerConfig plannerConfig, final AuthConfig authConfig, - final AuthenticatorMapper authenticatorMapper, final AuthorizerMapper authorizerMapper, + final Escalator escalator, final @Json ObjectMapper jsonMapper ) { @@ -89,7 +89,7 @@ public PlannerFactory( this.plannerConfig = plannerConfig; this.authConfig = authConfig; this.authorizerMapper = authorizerMapper; - this.authenticatorMapper = authenticatorMapper; + this.escalator = escalator; this.jsonMapper = jsonMapper; } @@ -151,9 +151,8 @@ public SqlConformance conformance() return new DruidPlanner( Frameworks.getPlanner(frameworkConfig), plannerContext, - authConfig, authorizerMapper, - authenticatorMapper + escalator ); } } diff --git a/sql/src/main/java/io/druid/sql/calcite/schema/DruidSchema.java b/sql/src/main/java/io/druid/sql/calcite/schema/DruidSchema.java index 11124a9cfeba..af52973cfcfe 100644 --- a/sql/src/main/java/io/druid/sql/calcite/schema/DruidSchema.java +++ b/sql/src/main/java/io/druid/sql/calcite/schema/DruidSchema.java @@ -50,8 +50,7 @@ import io.druid.server.QueryLifecycleFactory; import io.druid.server.coordination.DruidServerMetadata; import io.druid.server.security.AuthenticationResult; -import io.druid.server.security.Authenticator; -import io.druid.server.security.AuthenticatorMapper; +import io.druid.server.security.Escalator; import io.druid.sql.calcite.planner.PlannerConfig; import io.druid.sql.calcite.table.DruidTable; import io.druid.sql.calcite.table.RowSignature; @@ -117,8 +116,8 @@ public class DruidSchema extends AbstractSchema // All segments that need to be refreshed. private final TreeSet segmentsNeedingRefresh = new TreeSet<>(SEGMENT_ORDER); - // Escalating authenticator, so we can attach an authentication result to queries we generate. - private final Authenticator escalatingAuthenticator; + // Escalator, so we can attach an authentication result to queries we generate. + private final Escalator escalator; private boolean refreshImmediately = false; private long lastRefresh = 0L; @@ -130,7 +129,7 @@ public DruidSchema( final TimelineServerView serverView, final PlannerConfig config, final ViewManager viewManager, - final AuthenticatorMapper authenticatorMapper + final Escalator escalator ) { this.queryLifecycleFactory = Preconditions.checkNotNull(queryLifecycleFactory, "queryLifecycleFactory"); @@ -139,7 +138,7 @@ public DruidSchema( this.viewManager = Preconditions.checkNotNull(viewManager, "viewManager"); this.cacheExec = ScheduledExecutors.fixed(1, "DruidSchema-Cache-%d"); this.tables = new ConcurrentHashMap<>(); - this.escalatingAuthenticator = authenticatorMapper.getEscalatingAuthenticator(); + this.escalator = escalator; serverView.registerTimelineCallback( MoreExecutors.sameThreadExecutor(), @@ -410,7 +409,7 @@ private Set refreshSegmentsForDataSource( final Sequence sequence = runSegmentMetadataQuery( queryLifecycleFactory, Iterables.limit(segments, MAX_SEGMENTS_PER_QUERY), - escalatingAuthenticator.createEscalatedAuthenticationResult() + escalator.createEscalatedAuthenticationResult() ); Yielder yielder = Yielders.each(sequence); diff --git a/sql/src/test/java/io/druid/sql/avatica/DruidAvaticaHandlerTest.java b/sql/src/test/java/io/druid/sql/avatica/DruidAvaticaHandlerTest.java index bc49feb80786..bce883d1c534 100644 --- a/sql/src/test/java/io/druid/sql/avatica/DruidAvaticaHandlerTest.java +++ b/sql/src/test/java/io/druid/sql/avatica/DruidAvaticaHandlerTest.java @@ -41,10 +41,12 @@ import io.druid.java.util.common.StringUtils; import io.druid.math.expr.ExprMacroTable; import io.druid.server.DruidNode; +import io.druid.server.security.NoopEscalator; import io.druid.server.security.AuthConfig; import io.druid.server.security.AuthTestUtils; import io.druid.server.security.AuthenticatorMapper; import io.druid.server.security.AuthorizerMapper; +import io.druid.server.security.Escalator; import io.druid.sql.calcite.planner.Calcites; import io.druid.sql.calcite.planner.DruidOperatorTable; import io.druid.sql.calcite.planner.PlannerConfig; @@ -145,6 +147,7 @@ public void configure(Binder binder) binder.bindConstant().annotatedWith(Names.named("tlsServicePort")).to(-1); binder.bind(AuthenticatorMapper.class).toInstance(CalciteTests.TEST_AUTHENTICATOR_MAPPER); binder.bind(AuthorizerMapper.class).toInstance(CalciteTests.TEST_AUTHORIZER_MAPPER); + binder.bind(Escalator.class).toInstance(CalciteTests.TEST_AUTHENTICATOR_ESCALATOR); } } ) @@ -157,8 +160,8 @@ public void configure(Binder binder) macroTable, plannerConfig, new AuthConfig(), - CalciteTests.TEST_AUTHENTICATOR_MAPPER, CalciteTests.TEST_AUTHORIZER_MAPPER, + CalciteTests.TEST_AUTHENTICATOR_ESCALATOR, CalciteTests.getJsonMapper() ), AVATICA_CONFIG, @@ -719,8 +722,8 @@ public int getMaxRowsPerFrame() macroTable, plannerConfig, new AuthConfig(), - AuthTestUtils.TEST_AUTHENTICATOR_MAPPER, AuthTestUtils.TEST_AUTHORIZER_MAPPER, + new NoopEscalator(), CalciteTests.getJsonMapper() ), smallFrameConfig, diff --git a/sql/src/test/java/io/druid/sql/avatica/DruidStatementTest.java b/sql/src/test/java/io/druid/sql/avatica/DruidStatementTest.java index f2982102eee6..d229549d366e 100644 --- a/sql/src/test/java/io/druid/sql/avatica/DruidStatementTest.java +++ b/sql/src/test/java/io/druid/sql/avatica/DruidStatementTest.java @@ -24,6 +24,7 @@ import io.druid.java.util.common.DateTimes; import io.druid.math.expr.ExprMacroTable; import io.druid.server.security.AllowAllAuthenticator; +import io.druid.server.security.NoopEscalator; import io.druid.server.security.AuthConfig; import io.druid.server.security.AuthTestUtils; import io.druid.sql.calcite.planner.Calcites; @@ -75,8 +76,8 @@ public void setUp() throws Exception macroTable, plannerConfig, new AuthConfig(), - AuthTestUtils.TEST_AUTHENTICATOR_MAPPER, AuthTestUtils.TEST_AUTHORIZER_MAPPER, + new NoopEscalator(), CalciteTests.getJsonMapper() ); } diff --git a/sql/src/test/java/io/druid/sql/calcite/CalciteQueryTest.java b/sql/src/test/java/io/druid/sql/calcite/CalciteQueryTest.java index 35ccbbaa9141..5fed009c6dbd 100644 --- a/sql/src/test/java/io/druid/sql/calcite/CalciteQueryTest.java +++ b/sql/src/test/java/io/druid/sql/calcite/CalciteQueryTest.java @@ -6182,8 +6182,8 @@ private List getResults( macroTable, plannerConfig, new AuthConfig(), - CalciteTests.TEST_AUTHENTICATOR_MAPPER, CalciteTests.TEST_AUTHORIZER_MAPPER, + CalciteTests.TEST_AUTHENTICATOR_ESCALATOR, CalciteTests.getJsonMapper() ); diff --git a/sql/src/test/java/io/druid/sql/calcite/http/SqlResourceTest.java b/sql/src/test/java/io/druid/sql/calcite/http/SqlResourceTest.java index 31db7ca651e3..68d44524ae9d 100644 --- a/sql/src/test/java/io/druid/sql/calcite/http/SqlResourceTest.java +++ b/sql/src/test/java/io/druid/sql/calcite/http/SqlResourceTest.java @@ -30,6 +30,7 @@ import io.druid.query.QueryInterruptedException; import io.druid.query.ResourceLimitExceededException; import io.druid.server.security.AllowAllAuthenticator; +import io.druid.server.security.NoopEscalator; import io.druid.server.security.AuthConfig; import io.druid.server.security.AuthTestUtils; import io.druid.sql.calcite.planner.Calcites; @@ -108,8 +109,8 @@ public void setUp() throws Exception macroTable, plannerConfig, new AuthConfig(), - AuthTestUtils.TEST_AUTHENTICATOR_MAPPER, AuthTestUtils.TEST_AUTHORIZER_MAPPER, + new NoopEscalator(), CalciteTests.getJsonMapper() ) ); diff --git a/sql/src/test/java/io/druid/sql/calcite/schema/DruidSchemaTest.java b/sql/src/test/java/io/druid/sql/calcite/schema/DruidSchemaTest.java index 695646b1e3a3..dfdef39e8362 100644 --- a/sql/src/test/java/io/druid/sql/calcite/schema/DruidSchemaTest.java +++ b/sql/src/test/java/io/druid/sql/calcite/schema/DruidSchemaTest.java @@ -32,7 +32,7 @@ import io.druid.segment.QueryableIndex; import io.druid.segment.TestHelper; import io.druid.segment.incremental.IncrementalIndexSchema; -import io.druid.server.security.AuthTestUtils; +import io.druid.server.security.NoopEscalator; import io.druid.sql.calcite.planner.Calcites; import io.druid.sql.calcite.planner.PlannerConfig; import io.druid.sql.calcite.table.DruidTable; @@ -146,7 +146,7 @@ public void setUp() throws Exception new TestServerInventoryView(walker.getSegments()), PLANNER_CONFIG_DEFAULT, new NoopViewManager(), - AuthTestUtils.TEST_AUTHENTICATOR_MAPPER + new NoopEscalator() ); schema.start(); diff --git a/sql/src/test/java/io/druid/sql/calcite/util/CalciteTests.java b/sql/src/test/java/io/druid/sql/calcite/util/CalciteTests.java index df96dd8bde92..4e7d813d9a6b 100644 --- a/sql/src/test/java/io/druid/sql/calcite/util/CalciteTests.java +++ b/sql/src/test/java/io/druid/sql/calcite/util/CalciteTests.java @@ -58,8 +58,8 @@ import io.druid.query.aggregation.DoubleSumAggregatorFactory; import io.druid.query.aggregation.FloatSumAggregatorFactory; import io.druid.query.aggregation.hyperloglog.HyperUniquesAggregatorFactory; -import io.druid.query.expression.LookupExprMacro; import io.druid.query.expression.LookupEnabledTestExprMacroTable; +import io.druid.query.expression.LookupExprMacro; import io.druid.query.groupby.GroupByQuery; import io.druid.query.groupby.GroupByQueryConfig; import io.druid.query.groupby.GroupByQueryRunnerTest; @@ -96,12 +96,14 @@ import io.druid.server.security.Access; import io.druid.server.security.Action; import io.druid.server.security.AllowAllAuthenticator; +import io.druid.server.security.NoopEscalator; import io.druid.server.security.AuthConfig; import io.druid.server.security.AuthenticationResult; import io.druid.server.security.Authenticator; import io.druid.server.security.AuthenticatorMapper; import io.druid.server.security.Authorizer; import io.druid.server.security.AuthorizerMapper; +import io.druid.server.security.Escalator; import io.druid.server.security.Resource; import io.druid.server.security.ResourceType; import io.druid.sql.calcite.expression.SqlOperatorConversion; @@ -162,33 +164,38 @@ public Access authorize( static { final Map defaultMap = Maps.newHashMap(); defaultMap.put( - "allowAll", + AuthConfig.ALLOW_ALL_NAME, new AllowAllAuthenticator() { @Override public AuthenticationResult authenticateJDBCContext(Map context) { - return new AuthenticationResult((String) context.get("user"), "allowAll", null); - } - - @Override - public AuthenticationResult createEscalatedAuthenticationResult() - { - return new AuthenticationResult(TEST_SUPERUSER_NAME, "allowAll", null); + return new AuthenticationResult((String) context.get("user"), AuthConfig.ALLOW_ALL_NAME, null); } } ); - TEST_AUTHENTICATOR_MAPPER = new AuthenticatorMapper(defaultMap, "allowAll"); + TEST_AUTHENTICATOR_MAPPER = new AuthenticatorMapper(defaultMap); + } + public static final Escalator TEST_AUTHENTICATOR_ESCALATOR; + static { + TEST_AUTHENTICATOR_ESCALATOR = new NoopEscalator() { + + @Override + public AuthenticationResult createEscalatedAuthenticationResult() + { + return SUPER_USER_AUTH_RESULT; + } + }; } public static final AuthenticationResult REGULAR_USER_AUTH_RESULT = new AuthenticationResult( - "allowAll", - "allowAll", + AuthConfig.ALLOW_ALL_NAME, + AuthConfig.ALLOW_ALL_NAME, null ); public static final AuthenticationResult SUPER_USER_AUTH_RESULT = new AuthenticationResult( TEST_SUPERUSER_NAME, - "allowAll", + AuthConfig.ALLOW_ALL_NAME, null ); @@ -502,7 +509,7 @@ public static DruidSchema createMockSchema( new TestServerInventoryView(walker.getSegments()), plannerConfig, viewManager, - TEST_AUTHENTICATOR_MAPPER + TEST_AUTHENTICATOR_ESCALATOR ); schema.start();